mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Add the Record wire type, record registry rows, lift and extract adapters, and executor stack reservation
This commit is contained in:
@@ -352,6 +352,79 @@ impl<N> RecordSource<N> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Lifts a plain producer onto a record wire: the element lands at offset 0
|
||||
/// of a fresh element-only record. `Copy` elements only until droppable
|
||||
/// elements ride records.
|
||||
pub struct RecordLift<El, N> {
|
||||
edge: N,
|
||||
layout: Layout,
|
||||
frame_bytes: usize,
|
||||
_marker: std::marker::PhantomData<fn() -> El>,
|
||||
}
|
||||
|
||||
impl<El: Copy + 'static, N> RecordLift<El, N> {
|
||||
pub fn wire(edge: N) -> Self {
|
||||
let layout = Layout::default().with_writes(0, (size_of::<El>(), align_of::<El>()), &[]);
|
||||
let frame_bytes = layout.size.next_multiple_of(8);
|
||||
Self {
|
||||
edge,
|
||||
layout,
|
||||
frame_bytes,
|
||||
_marker: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'e, C, El, N> Node<C> for RecordLift<El, N>
|
||||
where
|
||||
C: crate::context::ExtractArena<ArenaRef = &'e crate::arena::Arena>,
|
||||
El: Copy + 'static,
|
||||
N: Node<C, Output = El>,
|
||||
{
|
||||
type Output = RecordValue<'e>;
|
||||
|
||||
fn eval(&self, input: &C) -> GPoll<RecordValue<'e>> {
|
||||
let dst = stack::push(self.frame_bytes);
|
||||
let value = self.edge.eval(input).map(|element| {
|
||||
unsafe { write_field(dst, 0, element) };
|
||||
RecordValue::from_rec(unsafe { Rec::new(dst.cast_const()) })
|
||||
});
|
||||
stack::pop(dst);
|
||||
value
|
||||
}
|
||||
|
||||
fn layout(&self) -> Option<&Layout> {
|
||||
Some(&self.layout)
|
||||
}
|
||||
}
|
||||
|
||||
/// Extracts the element from a record wire for a plain consumer.
|
||||
pub struct RecordExtract<El, N> {
|
||||
edge: N,
|
||||
_marker: std::marker::PhantomData<fn() -> El>,
|
||||
}
|
||||
|
||||
impl<El, N> RecordExtract<El, N> {
|
||||
pub fn wire(edge: N) -> Self {
|
||||
Self {
|
||||
edge,
|
||||
_marker: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'e, C, El, N> Node<C> for RecordExtract<El, N>
|
||||
where
|
||||
El: Copy + 'static,
|
||||
N: Node<C, Output = RecordValue<'e>>,
|
||||
{
|
||||
type Output = El;
|
||||
|
||||
fn eval(&self, input: &C) -> GPoll<El> {
|
||||
self.edge.eval(input).map(|value| unsafe { value.rec().element::<El>() })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'e, C, N> Node<C> for RecordSource<N>
|
||||
where
|
||||
N: Node<C, Output = RecordValue<'e>>,
|
||||
|
||||
@@ -79,6 +79,12 @@ pub type ErasedLendNode<T> = dyn for<'c> Node<ContextImpl<'c>, Output = &'c T> +
|
||||
#[cfg(target_family = "wasm")]
|
||||
pub type ErasedLendNode<T> = dyn for<'c> Node<ContextImpl<'c>, Output = &'c T>;
|
||||
|
||||
/// Element-independent by erasure; the wire's `Type::Record(El)` keeps element reads proven at wiring.
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
pub type ErasedRecordNode = dyn for<'c> Node<ContextImpl<'c>, Output = crate::record::RecordValue<'c>> + Send + Sync;
|
||||
#[cfg(target_family = "wasm")]
|
||||
pub type ErasedRecordNode = dyn for<'c> Node<ContextImpl<'c>, Output = crate::record::RecordValue<'c>>;
|
||||
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
type DynEdge = dyn std::any::Any + Send + Sync;
|
||||
#[cfg(target_family = "wasm")]
|
||||
@@ -96,6 +102,22 @@ pub fn lend_edge_type<T: 'static>() -> Type {
|
||||
Type::Fn(Box::new(concrete!(Context)), Box::new(ref_type::<T>()))
|
||||
}
|
||||
|
||||
pub fn record_type<T: 'static>() -> Type {
|
||||
Type::Record(Box::new(concrete!(T)))
|
||||
}
|
||||
|
||||
pub fn record_edge_type<T: 'static>() -> Type {
|
||||
Type::Fn(Box::new(concrete!(Context)), Box::new(record_type::<T>()))
|
||||
}
|
||||
|
||||
/// The record edge type of a token row, generic over the element.
|
||||
pub fn generic_record_edge_type(name: &'static str) -> Type {
|
||||
Type::Fn(
|
||||
Box::new(concrete!(Context)),
|
||||
Box::new(Type::Record(Box::new(Type::Generic(std::borrow::Cow::Borrowed(name))))),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn cache_key<C: CacheHash + ?Sized>(ctx: &C) -> u64 {
|
||||
let mut hasher = graphene_hash::FxHasher64::new();
|
||||
ctx.cache_hash(&mut hasher);
|
||||
@@ -106,6 +128,7 @@ pub fn cache_key<C: CacheHash + ?Sized>(ctx: &C) -> u64 {
|
||||
pub enum ConstructionError {
|
||||
Arity { expected: usize, got: usize },
|
||||
Type { expected: Box<Type>, found: Box<Type> },
|
||||
MissingLayout,
|
||||
}
|
||||
|
||||
pub struct SharedEdge<N: ?Sized> {
|
||||
@@ -198,6 +221,10 @@ impl EdgeHandle {
|
||||
Self::new_erased(node, lend_edge_type::<T>())
|
||||
}
|
||||
|
||||
pub fn new_record<T: 'static>(node: std::sync::Arc<ErasedRecordNode>) -> Self {
|
||||
Self::new_erased(node, record_edge_type::<T>())
|
||||
}
|
||||
|
||||
pub fn new_erased<N>(node: std::sync::Arc<N>, ty: Type) -> Self
|
||||
where
|
||||
N: ?Sized + 'static + for<'c> Node<ContextImpl<'c>>,
|
||||
@@ -242,6 +269,10 @@ impl EdgeHandle {
|
||||
self.downcast_erased(lend_edge_type::<T>())
|
||||
}
|
||||
|
||||
pub fn downcast_record<T: 'static>(self) -> Result<SharedEdge<ErasedRecordNode>, ConstructionError> {
|
||||
self.downcast_erased(record_edge_type::<T>())
|
||||
}
|
||||
|
||||
pub fn downcast_erased<N: ?Sized + 'static>(self, expected: Type) -> Result<SharedEdge<N>, ConstructionError> {
|
||||
let found = self.ty;
|
||||
self.node.downcast::<SharedEdge<N>>().map(|edge| *edge).map_err(|_| ConstructionError::Type {
|
||||
|
||||
@@ -236,6 +236,8 @@ pub enum Type {
|
||||
/// Represents a future which promises to return the inner type.
|
||||
Future(Box<Type>),
|
||||
Ref(Box<Type>),
|
||||
/// A packed record wire over the element type; the layout stays node-resident metadata.
|
||||
Record(Box<Type>),
|
||||
}
|
||||
|
||||
impl Default for Type {
|
||||
@@ -310,6 +312,7 @@ impl Type {
|
||||
Self::Fn(_, _) => None,
|
||||
Self::Future(_) => None,
|
||||
Self::Ref(_) => None,
|
||||
Self::Record(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,6 +323,7 @@ impl Type {
|
||||
Self::Fn(_, _) => None,
|
||||
Self::Future(_) => None,
|
||||
Self::Ref(_) => None,
|
||||
Self::Record(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,6 +334,7 @@ impl Type {
|
||||
Self::Fn(_, output) => output.nested_type(),
|
||||
Self::Future(output) => output.nested_type(),
|
||||
Self::Ref(inner) => inner.nested_type(),
|
||||
Self::Record(inner) => inner.nested_type(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,6 +348,7 @@ impl Type {
|
||||
Self::Fn(_, output) => output.replace_nested(f),
|
||||
Self::Future(output) => output.replace_nested(f),
|
||||
Self::Ref(inner) => inner.replace_nested(f),
|
||||
Self::Record(inner) => inner.replace_nested(f),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,6 +359,7 @@ impl Type {
|
||||
Type::Fn(call_arg, return_value) => format!("{} called with {}", return_value.identifier_name(), call_arg.identifier_name()),
|
||||
Type::Future(ty) => ty.identifier_name(),
|
||||
Type::Ref(ty) => ty.identifier_name(),
|
||||
Type::Record(ty) => ty.identifier_name(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -448,6 +455,7 @@ impl std::fmt::Display for Type {
|
||||
Type::Fn(_, return_value) => write!(f, "{return_value}"),
|
||||
Type::Future(ty) => write!(f, "{ty}"),
|
||||
Type::Ref(ty) => write!(f, "{ty}"),
|
||||
Type::Record(ty) => write!(f, "{ty}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user