Introduce the serve surface: the frame claim's proof-bearing lift on Node

This commit is contained in:
Dennis Kobert
2026-08-28 19:18:54 +00:00
parent aef750153b
commit f3e945c5d8
2 changed files with 38 additions and 0 deletions

View File

@@ -314,11 +314,31 @@ impl<T: Copy> Iterator for ListIter<'_, T> {
}
}
/// The output marker of a node that serves records through the caller's
/// frame claim instead of returning a plain value. It satisfies the lift
/// bounds so [`Node::serve`] stays callable and overridable on the erased
/// surface.
#[derive(Clone, Copy, Debug, Default, PartialEq, dyn_any::DynAny)]
pub struct Records;
pub trait Node<Input> {
type Output;
fn eval(&self, input: &Input) -> GPoll<Self::Output>;
/// Serves the node's record through the caller's claim: the writes land
/// in the claim and the returned proof is mintable only by its closing
/// methods, so the served record is of the claimed layout by
/// construction. The default lifts a plain output's element; record
/// servers override it.
fn serve<'e, 'l>(&self, input: &Input, slot: crate::record::FrameClaim<'l>) -> GPoll<crate::record::Served<'e>>
where
Self::Output: Send + Sync + dyn_any::StaticTypeSized,
Input: crate::context::ExtractArena<ArenaRef = &'e crate::arena::Arena>,
{
slot.lift_served(self.eval(input), input.arena())
}
/// The count of items at one absolute nesting level (innermost `0`). The
/// leveled primitive a structure node overrides to report a pushed level's
/// size; the scalar base is one item at every level. Uncertainty rides the

View File

@@ -1801,6 +1801,24 @@ impl<'l> FrameClaim<'l> {
None => unsafe { (&raw mut self.inline).cast::<RecordValue<'e>>().read() },
}
}
/// [`Self::lift`] with the proof-bearing return for [`Node::serve`].
pub fn lift_served<'e, T: Send + Sync + dyn_any::StaticTypeSized>(self, poll: GPoll<T>, arena: &'e crate::arena::Arena) -> GPoll<Served<'e>> {
self.lift(poll, arena).map(|value| Served { value })
}
}
/// The proof a record was served through a frame claim: mintable only by the
/// claim's closing methods, so holding one means the record is of the
/// claimed layout.
pub struct Served<'e> {
value: RecordValue<'e>,
}
impl<'e> Served<'e> {
pub fn value(self) -> RecordValue<'e> {
self.value
}
}
impl Drop for FrameClaim<'_> {