diff --git a/node-graph/libraries/core-types/src/node.rs b/node-graph/libraries/core-types/src/node.rs index ab3925f4cb..947840513c 100644 --- a/node-graph/libraries/core-types/src/node.rs +++ b/node-graph/libraries/core-types/src/node.rs @@ -153,7 +153,7 @@ impl<'a> RecordBatchMut<'a> { /// One lane's record: its pointer paired with the batch's layout. #[derive(Clone, Copy, Debug)] pub struct RecordLane<'a> { - rec: crate::record::Rec, + rec: crate::record::Rec<'a>, layout: &'a crate::record::Layout, } @@ -162,7 +162,7 @@ impl<'a> RecordLane<'a> { self.layout } - pub fn rec(&self) -> crate::record::Rec { + pub fn rec(&self) -> crate::record::Rec<'a> { self.rec } diff --git a/node-graph/libraries/core-types/src/record.rs b/node-graph/libraries/core-types/src/record.rs index 0f9822897f..624ed032eb 100644 --- a/node-graph/libraries/core-types/src/record.rs +++ b/node-graph/libraries/core-types/src/record.rs @@ -188,10 +188,10 @@ impl Layout { /// Resolves a value of this layout, which must be its wiring-proven one, /// to its record bytes. An empty record carries nothing and resolves to the /// value's own storage; every other record spills and rides the pointer. - pub fn rec(&self, value: &RecordValue<'_>) -> Rec { + pub fn rec<'v>(&self, value: &'v RecordValue<'_>) -> Rec<'v> { match self.size == 0 { - true => Rec((&raw const *value).cast()), - false => Rec(value.ptr), + true => Rec((&raw const *value).cast(), std::marker::PhantomData), + false => Rec(value.ptr, std::marker::PhantomData), } } @@ -398,16 +398,17 @@ impl LayoutMeta { } } -/// A view of one record: a pointer whose layout is proven at wiring. +/// A view of one record: a pointer whose layout is proven at wiring, borrowing +/// the storage it points into for `'r`. #[derive(Clone, Copy, Debug)] -pub struct Rec(*const u8); +pub struct Rec<'r>(*const u8, std::marker::PhantomData<&'r u8>); -impl Rec { +impl<'r> Rec<'r> { /// # Safety /// `ptr` must point to a live record of the layout the consumer resolved - /// at wiring, valid until the owning slot is next written. + /// at wiring, valid for `'r` and until the owning slot is next written. pub unsafe fn new(ptr: *const u8) -> Self { - Rec(ptr) + Rec(ptr, std::marker::PhantomData) } /// # Safety @@ -467,7 +468,7 @@ impl<'e> RecordValue<'e> { } #[doc(hidden)] - pub fn spilled(rec: Rec) -> Self { + pub fn spilled(rec: Rec<'_>) -> Self { RecordValue { ptr: rec.ptr(), _lifetime: std::marker::PhantomData, @@ -693,7 +694,7 @@ impl<'a, 'e, N> RecordEdgeInput<'a, 'e, N> { /// # Safety /// `rec` must be a record of the layout the offsets were resolved against /// and `El` its element type; both are proven at wiring. -unsafe fn element_only(rec: Rec, _reads: &[Option]) -> El { +unsafe fn element_only(rec: Rec<'_>, _reads: &[Option]) -> El { unsafe { read_element::(rec) } } @@ -701,7 +702,7 @@ pub struct ElementEdge<'a, 'e, Out, N> { node: &'a N, layout: &'a Layout, reads: &'a [Option], - read: unsafe fn(Rec, &[Option]) -> Out, + read: unsafe fn(Rec<'_>, &[Option]) -> Out, frames: &'a Frames<'e>, } @@ -720,7 +721,7 @@ impl<'a, 'e, El: Clone, N> ElementEdge<'a, 'e, El, N> { impl<'a, 'e, Out, N> ElementEdge<'a, 'e, Out, N> { /// `read` must be sound against the layout the offsets in `reads` were /// resolved from; the macro proves both at wiring. - pub fn with_reads(node: &'a N, layout: &'a Layout, reads: &'a [Option], read: unsafe fn(Rec, &[Option]) -> Out, frames: &'a Frames<'e>) -> Self { + pub fn with_reads(node: &'a N, layout: &'a Layout, reads: &'a [Option], read: unsafe fn(Rec<'_>, &[Option]) -> Out, frames: &'a Frames<'e>) -> Self { Self { node, layout, reads, read, frames } } @@ -752,7 +753,7 @@ pub struct ElementLazyInput<'a, 'e, Out, N> { input_index: usize, layout: &'a Layout, reads: &'a [Option], - read: unsafe fn(Rec, &[Option]) -> Out, + read: unsafe fn(Rec<'_>, &[Option]) -> Out, frames: &'a Frames<'e>, } @@ -779,7 +780,7 @@ impl<'a, 'e, Out, N> ElementLazyInput<'a, 'e, Out, N> { input_index: usize, layout: &'a Layout, reads: &'a [Option], - read: unsafe fn(Rec, &[Option]) -> Out, + read: unsafe fn(Rec<'_>, &[Option]) -> Out, frames: &'a Frames<'e>, ) -> Self { Self { @@ -916,7 +917,7 @@ pub struct DerivedLazyInput<'a, 'e, Out, N> { input_index: usize, inner_levels: u8, reads: &'a [Option], - read: unsafe fn(Rec, &[Option]) -> Out, + read: unsafe fn(Rec<'_>, &[Option]) -> Out, frames: &'a Frames<'e>, } @@ -929,7 +930,7 @@ impl<'a, 'e, Out, N> DerivedLazyInput<'a, 'e, Out, N> { input_index: usize, inner_levels: u8, reads: &'a [Option], - read: unsafe fn(Rec, &[Option]) -> Out, + read: unsafe fn(Rec<'_>, &[Option]) -> Out, frames: &'a Frames<'e>, ) -> Self { Self { @@ -968,7 +969,7 @@ impl<'a, 'e, Out, N> DerivedLazyInput<'a, 'e, Out, N> { /// /// # Safety /// `rec` must be a spilled record's frame. -pub unsafe fn token_only<'e>(rec: Rec, _reads: &[Option]) -> RecordValue<'e> { +pub unsafe fn token_only<'e>(rec: Rec<'_>, _reads: &[Option]) -> RecordValue<'e> { RecordValue::spilled(rec) } @@ -1433,7 +1434,7 @@ where /// # Safety /// The record's element must be a `T` in the form [`element_parked`] picks, /// and the borrow is only valid while the record is. -pub unsafe fn borrow_element<'e, T>(rec: Rec) -> &'e T { +pub unsafe fn borrow_element<'e, T>(rec: Rec<'_>) -> &'e T { match element_parked::() { true => unsafe { rec.element::<&T>() }, false => unsafe { &*rec.ptr().cast::() }, @@ -1442,7 +1443,7 @@ pub unsafe fn borrow_element<'e, T>(rec: Rec) -> &'e T { /// # Safety /// The record's element must be a `T` in the form [`element_parked`] picks. -pub unsafe fn read_element(rec: Rec) -> T { +pub unsafe fn read_element(rec: Rec<'_>) -> T { unsafe { borrow_element::(rec) }.clone() } @@ -1466,7 +1467,7 @@ pub unsafe fn write_element(dst: *mut u8, value: T, arena: &crat /// # Safety /// `src` must be a record of the plan's source layout and `dst` a buffer of /// the plan's target layout; both are proven at wiring. -pub unsafe fn apply_plan(src: Rec, dst: *mut u8, plan: &[(usize, usize, usize)]) { +pub unsafe fn apply_plan(src: Rec<'_>, dst: *mut u8, plan: &[(usize, usize, usize)]) { for &(from, to, size) in plan { unsafe { std::ptr::copy_nonoverlapping(src.ptr().add(from), dst.add(to), size) }; } @@ -1512,8 +1513,9 @@ impl SourcePlan { /// # Safety /// `src` must be a record of this plan's source layout and `dst` a - /// buffer of the plan's union layout. - pub unsafe fn translate(&self, src: Rec, dst: *mut u8) -> Rec { + /// buffer of the plan's union layout. The returned view borrows `dst`, so + /// `'d` must not outlive it. + pub unsafe fn translate<'d>(&self, src: Rec<'_>, dst: *mut u8) -> Rec<'d> { unsafe { apply_plan(src, dst, &self.moves); for (offset, bytes) in &self.fills { @@ -1549,7 +1551,7 @@ impl RecordSource { /// # Safety /// `rec` must be a live record of `layout`. -pub unsafe fn copy_record_bytes(layout: &Layout, rec: Rec) -> Box<[u8]> { +pub unsafe fn copy_record_bytes(layout: &Layout, rec: Rec<'_>) -> Box<[u8]> { unsafe { std::slice::from_raw_parts(rec.ptr(), layout.size) }.into() } @@ -1598,7 +1600,7 @@ impl<'e, 'l> FrameClaim<'e, 'l> { /// # Safety /// `src` must be a live record of the plan's source layout, and the plan /// must be the wiring-resolved plan of this frame's layout. - pub unsafe fn carry(&mut self, src: Rec, plan: &[(usize, usize, usize)]) { + pub unsafe fn carry(&mut self, src: Rec<'_>, plan: &[(usize, usize, usize)]) { unsafe { apply_plan(src, self.dst(), plan) }; } @@ -1688,7 +1690,7 @@ impl<'e, 'l> FrameClaim<'e, 'l> { /// # Safety /// `src` must be a live record of `plan`'s source layout, and `plan` must /// translate into this frame's layout. - pub unsafe fn translate(&mut self, src: Rec, plan: &SourcePlan) { + pub unsafe fn translate(&mut self, src: Rec<'_>, plan: &SourcePlan) { unsafe { plan.translate(src, self.dst()) }; } } @@ -1804,7 +1806,7 @@ impl std::fmt::Debug for OwnedRecord { impl OwnedRecord { /// # Safety /// `rec` must be a live record of `layout`. - pub unsafe fn copy_out(layout: &Layout, rec: Rec) -> OwnedRecord { + pub unsafe fn copy_out(layout: &Layout, rec: Rec<'_>) -> OwnedRecord { let bytes: Box<[u8]> = unsafe { std::slice::from_raw_parts(rec.ptr(), layout.size) }.into(); let element = layout.element.parked.then(|| unsafe { (layout.element.clone_out)(rec.ptr()) }); let fields = layout diff --git a/node-graph/node-macro/src/codegen.rs b/node-graph/node-macro/src/codegen.rs index 7821ca397d..ccc7dacb14 100644 --- a/node-graph/node-macro/src/codegen.rs +++ b/node-graph/node-macro/src/codegen.rs @@ -2721,7 +2721,7 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn /// # Safety /// `__rec` must be a spilled record's frame, of the layout /// `__reads` was resolved against; the token rebinds it. - unsafe fn #read_fn<'__read>(__rec: #core_types::record::Rec, __reads: &[Option]) -> (#core_types::record::RecordValue<'__read> #(, #attr_tys)*) { + unsafe fn #read_fn<'__read>(__rec: #core_types::record::Rec<'_>, __reads: &[Option]) -> (#core_types::record::RecordValue<'__read> #(, #attr_tys)*) { (#core_types::record::RecordValue::spilled(__rec) #(, #attr_slots)*) } }; @@ -2730,7 +2730,7 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn /// # Safety /// `__rec` must be a record whose element is the declared output /// type, of the layout `__reads` was resolved against. - unsafe fn #read_fn<'__read #(, #generics)*>(__rec: #core_types::record::Rec, __reads: &[Option]) -> (#output_type #(, #attr_tys)*) + unsafe fn #read_fn<'__read #(, #generics)*>(__rec: #core_types::record::Rec<'_>, __reads: &[Option]) -> (#output_type #(, #attr_tys)*) where #output_type: ::core::clone::Clone, {