Skip to main content

cel_runtime/
dyn_closure.rs

1//! A first-class, callable CEL value: a compiled body plus its declared signature.
2//!
3//! See `docs/superpowers/specs/2026-08-21-cel-closures-design.md` for the full design rationale
4//! (why `Rc`, why `RefCell`, why no captured environment).
5//!
6//! # Examples
7//!
8//! Build a closure that adds two `i32` values, then call it with different arguments:
9//!
10//! ```rust
11//! use cel_runtime::{DynClosure, DynSegment};
12//! use std::any::TypeId;
13//!
14//! // Compile a body that takes two i32 arguments and returns their sum.
15//! let mut body = DynSegment::new::<()>();
16//! body.push_arg::<i32>(0);
17//! body.push_arg::<i32>(1);
18//! body.op2(|a: i32, b: i32| a + b).unwrap();
19//!
20//! // Wrap it as a callable closure with its declared signature.
21//! let closure = DynClosure::new(
22//!     vec![TypeId::of::<i32>(), TypeId::of::<i32>()],
23//!     TypeId::of::<i32>(),
24//!     body,
25//! );
26//!
27//! // Call the closure multiple times with different arguments.
28//! let (a, b) = (2i32, 3i32);
29//! assert_eq!(closure.call::<i32>(&[&a, &b]).unwrap(), 5);
30//!
31//! let (c, d) = (10i32, 20i32);
32//! assert_eq!(closure.call::<i32>(&[&c, &d]).unwrap(), 30);
33//! ```
34
35use std::any::{Any, TypeId};
36use std::cell::{Cell, RefCell};
37use std::rc::Rc;
38
39use crate::ValueType;
40use crate::dyn_segment::DynSegment;
41
42/// An exact compile-time callable shape, including nested aggregate and callable results.
43#[derive(Clone, Debug)]
44pub(crate) struct ClosureSignature {
45    pub(crate) parameters: Vec<ValueType>,
46    pub(crate) result: ValueType,
47}
48
49impl ClosureSignature {
50    /// Converts known recursive metadata without changing canonical storage.
51    ///
52    /// # Errors
53    /// Returns an error for missing or mismatched leaf factories, unknown nested
54    /// callable signatures, or an unrepresentable canonical tuple layout.
55    /// - Complexity: O(n) traversal time and output space for n signature nodes,
56    ///   excluding leaf factory costs.
57    fn complete(
58        &self,
59        leaf: &mut impl FnMut(TypeId) -> Option<crate::value_type::ValueType>,
60    ) -> anyhow::Result<crate::value_type::ValueType> {
61        let parameters = self
62            .parameters
63            .iter()
64            .map(|parameter| enrich_value_type(parameter, leaf))
65            .collect::<anyhow::Result<Vec<_>>>()?;
66        Ok(crate::value_type::ValueType::callable(
67            parameters,
68            enrich_value_type(&self.result, leaf)?,
69        ))
70    }
71}
72
73/// Resolves one concrete registered leaf through a previously monomorphized factory.
74///
75/// # Errors
76/// Returns an error if the factory is missing, structural, or describes another
77/// concrete type or layout. A closure marker without a signature is rejected.
78fn complete_leaf(
79    id: TypeId,
80    size: usize,
81    align: usize,
82    leaf: &mut impl FnMut(TypeId) -> Option<crate::value_type::ValueType>,
83) -> anyhow::Result<crate::value_type::ValueType> {
84    anyhow::ensure!(
85        id != TypeId::of::<DynClosure>(),
86        "closure signature metadata is unavailable"
87    );
88    let complete =
89        leaf(id).ok_or_else(|| anyhow::anyhow!("complete leaf factory is unavailable"))?;
90    complete.validate_opaque_leaf(id)?;
91    anyhow::ensure!(
92        complete.layout().size() == size && complete.layout().align() == align,
93        "complete leaf factory layout mismatch"
94    );
95    Ok(complete)
96}
97
98/// Enriches canonical signature leaves through explicitly supplied factories.
99///
100/// # Errors
101/// Returns an error for unavailable signatures/factories or invalid tuple layout.
102/// - Complexity: O(n) time and output space for n recursive descriptor nodes.
103fn enrich_value_type(
104    value: &ValueType,
105    leaf: &mut impl FnMut(TypeId) -> Option<crate::value_type::ValueType>,
106) -> anyhow::Result<crate::value_type::ValueType> {
107    use crate::value_type::{AssociatedType, ValueType as Complete};
108    match value.kind() {
109        crate::ValueKind::Tuple(fields) => Complete::tuple(
110            fields
111                .iter()
112                .map(|field| {
113                    Ok(AssociatedType {
114                        offset: 0,
115                        value_type: enrich_value_type(&field.value_type, leaf)?,
116                    })
117                })
118                .collect::<anyhow::Result<Vec<_>>>()?,
119        ),
120        crate::ValueKind::Array(element) => Ok(Complete::array(enrich_value_type(element, leaf)?)),
121        crate::ValueKind::Callable { parameters, result } => Ok(Complete::callable(
122            parameters
123                .iter()
124                .map(|parameter| enrich_value_type(parameter, leaf))
125                .collect::<anyhow::Result<_>>()?,
126            enrich_value_type(result, leaf)?,
127        )),
128        crate::ValueKind::Leaf(id) => complete_leaf(*id, value.size(), value.align(), leaf),
129    }
130}
131
132/// Compares complete known signatures without relying on the erased closure marker.
133///
134/// - Complexity: O(number of recursive type nodes).
135#[cfg(test)]
136pub(crate) fn same_signature(
137    left: Option<&ClosureSignature>,
138    right: Option<&ClosureSignature>,
139) -> bool {
140    match (left, right) {
141        (None, None) => true,
142        (Some(a), Some(b)) => {
143            a.parameters.len() == b.parameters.len()
144                && a.parameters
145                    .iter()
146                    .zip(&b.parameters)
147                    .all(|(a, b)| a.same_shape(b))
148                && a.result.same_shape(&b.result)
149        }
150        _ => false,
151    }
152}
153
154/// A monomorphized dispatcher for [`DynClosure::call_boxed`]: runs a closure's body via
155/// `DynSegment::call_dyn::<R>` for some concrete `R` the dispatcher itself already knows, boxing
156/// the result so the caller (which only knows `R` dynamically, as a `TypeId`) doesn't need to.
157pub type CallDynFn = fn(&mut DynSegment, &[&dyn Any]) -> anyhow::Result<Box<dyn Any>>;
158
159/// Invokes an exact construction-bound payload and initializes output on success only.
160///
161/// Both frame pointers and the payload must match the dispatcher's concrete types.
162pub(crate) type FrameDispatch = unsafe fn(*mut (), *const u8, *mut u8) -> anyhow::Result<()>;
163
164/// Owns either a compiler-facing body or a private type-bound frame dispatcher.
165enum ClosureBody {
166    Interpreted(DynSegment),
167    Framed {
168        payload: Box<dyn Any>,
169        dispatch: FrameDispatch,
170    },
171}
172
173impl ClosureBody {
174    /// Returns the compiler-facing body, rejecting immutable typed facade bodies.
175    ///
176    /// # Errors
177    /// Rejects framed native and prepared bodies.
178    fn segment(&mut self) -> anyhow::Result<&mut DynSegment> {
179        match self {
180            Self::Interpreted(body) => Ok(body),
181            Self::Framed { .. } => anyhow::bail!("typed callable has no mutable compiler body"),
182        }
183    }
184}
185
186/// Binds a canonical contiguous argument frame and a raw interpreted result once.
187struct FramePlan {
188    offsets: Vec<usize>,
189    result: crate::container_execution::ResultPlan,
190}
191
192/// Shares one body and counts live trusted-binding leases across all carrier aliases.
193struct ClosureData {
194    param_types: Vec<TypeId>,
195    return_type: TypeId,
196    body: RefCell<ClosureBody>,
197    frame: Option<FramePlan>,
198    signature: Option<std::sync::Arc<ClosureSignature>>,
199    trusted_bindings: Cell<usize>,
200}
201
202/// Prevents arbitrary mutable body dispatch until this independent lease is dropped.
203///
204/// Holds the shared carrier alive; moving the lease preserves the freeze, and
205/// dropping it releases exactly one binding even during unwinding. Carrier clones
206/// share the counter but neither acquire nor release leases themselves.
207pub(crate) struct TrustedBindingLease {
208    closure: DynClosure,
209}
210
211impl Drop for TrustedBindingLease {
212    /// Decrements the lease count without borrowing the body, before releasing the carrier.
213    fn drop(&mut self) {
214        let bindings = &self.closure.0.trusted_bindings;
215        debug_assert!(bindings.get() > 0);
216        bindings.set(bindings.get() - 1);
217    }
218}
219
220/// `Debug` implementation that formats the closure's signature but deliberately omits `body` from the output
221/// (via `finish_non_exhaustive`), since `DynSegment` is not easily debuggable and the signature alone
222/// is typically what callers need to see.
223impl std::fmt::Debug for ClosureData {
224    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
225        f.debug_struct("ClosureData")
226            .field("param_types", &self.param_types)
227            .field("return_type", &self.return_type)
228            .finish_non_exhaustive()
229    }
230}
231
232/// A first-class, callable CEL value: a compiled body plus its declared parameter/return types.
233///
234/// Holds no captured environment — only its own parameters resolve inside `body`. Calling it
235/// twice with different `args` is exactly as fresh each time as calling any other `DynSegment`.
236/// `Rc`-wrapped so `Clone` never requires `DynSegment` itself to implement `Clone` (it doesn't —
237/// see the design spec); `RefCell` because callers only ever reach a `DynClosure` through `&self`
238/// (matching `adam_rs::Filter`/`Method`'s `Fn`, not `FnMut`, storage), while `DynSegment`'s own
239/// call methods need `&mut self`.
240#[derive(Clone, Debug)]
241pub struct DynClosure(Rc<ClosureData>, Option<Rc<TrustedBindingLease>>);
242
243impl std::fmt::Debug for TrustedBindingLease {
244    /// Formats the lease without recursively traversing its retained carrier.
245    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
246        f.write_str("TrustedBindingLease")
247    }
248}
249
250impl DynClosure {
251    /// Shares a construction-bound frame dispatcher without exposing its payload.
252    ///
253    /// A prepared payload owns its immutable body and all nested trusted leases.
254    ///
255    /// # Safety
256    /// `dispatch` must match `payload` and the facade's exact Rust signature.
257    /// On success it must initialize exactly one result; on error or unwind it
258    /// must leave output uninitialized. If supplied, metadata must describe that
259    /// exact signature.
260    /// - Complexity: O(p) parameter metadata storage for p declared parameters.
261    pub(crate) unsafe fn from_frame_body(
262        payload: Box<dyn Any>,
263        dispatch: FrameDispatch,
264        signature: Option<ClosureSignature>,
265    ) -> Self {
266        let param_types = signature
267            .as_ref()
268            .map(|s| s.parameters.iter().map(ValueType::type_id).collect())
269            .unwrap_or_default();
270        let return_type = signature
271            .as_ref()
272            .map(|s| s.result.type_id())
273            .unwrap_or(TypeId::of::<()>());
274        Self(
275            Rc::new(ClosureData {
276                param_types,
277                return_type,
278                body: RefCell::new(ClosureBody::Framed { payload, dispatch }),
279                frame: None,
280                signature: signature.map(std::sync::Arc::new),
281                trusted_bindings: Cell::new(0),
282            }),
283            None,
284        )
285    }
286
287    /// Dispatches a complete preparation-validated contiguous borrowed argument frame.
288    ///
289    /// # Safety
290    /// Both frame pointers must match this exact carrier's validated signature.
291    /// Output is aligned uninitialized result storage. A compiler-facing interpreted body
292    /// must be protected by a trusted lease for the duration of the call.
293    /// # Errors
294    /// Returns reentrant entry or original body errors without initializing output.
295    /// - Complexity: Body-dependent; interpreted bodies set up O(a) pointers.
296    pub(crate) unsafe fn call_frame_trusted(
297        &self,
298        args: *const u8,
299        result: *mut u8,
300    ) -> anyhow::Result<()> {
301        let mut body = self
302            .0
303            .body
304            .try_borrow_mut()
305            .map_err(|_| anyhow::anyhow!("closure body is already executing"))?;
306        match &mut *body {
307            ClosureBody::Framed { payload, dispatch } => {
308                // Erasing an Any pointer preserves the boxed concrete data
309                // address; construction binds its monomorphized dispatcher.
310                let pointer = std::ptr::from_mut(payload.as_mut()).cast::<()>();
311                unsafe { dispatch(pointer, args, result) }
312            }
313            ClosureBody::Interpreted(body) => {
314                let frame = self.0.frame.as_ref().expect("validated canonical body");
315                let arguments: Vec<_> = frame
316                    .offsets
317                    .iter()
318                    .map(|offset| unsafe { args.add(*offset) })
319                    .collect();
320                let mut stack = unsafe { body.execute_raw(&arguments)? };
321                let mut output = unsafe { frame.result.take(&mut stack) };
322                unsafe { output.move_into(result) };
323                Ok(())
324            }
325        }
326    }
327
328    /// Returns the complete canonical callable descriptor after validating its current body.
329    ///
330    /// # Errors
331    /// Rejects untyped closures, executing bodies, or bodies changed incompatibly
332    /// through an unfrozen mutable dispatcher.
333    /// - Complexity: O(n) complete comparisons for n signature/body descriptor nodes.
334    ///
335    /// # Examples
336    /// ```
337    /// let mut body = cel_runtime::DynSegment::new::<()>(); body.just(7i32);
338    /// let closure = cel_runtime::DynClosure::typed(vec![], body).unwrap();
339    /// assert!(matches!(closure.value_type().unwrap().kind(), cel_runtime::ValueKind::Callable { .. }));
340    /// ```
341    pub fn value_type(&self) -> anyhow::Result<ValueType> {
342        self.validate_body_signature()?;
343        let signature = self
344            .0
345            .signature
346            .as_ref()
347            .expect("validated typed signature");
348        Ok(ValueType::callable(
349            signature.parameters.clone(),
350            signature.result.clone(),
351        ))
352    }
353
354    /// Wraps `body` as a closure value declaring `param_types` (in order) and `return_type`.
355    ///
356    /// - Precondition: `body` was compiled expecting exactly `param_types.len()` positional
357    ///   arguments (via `push_arg`/`push_argument`), in that order, and
358    ///   produces exactly one result of `return_type`.
359    ///
360    /// # Examples
361    ///
362    /// ```rust
363    /// use cel_runtime::{DynClosure, DynSegment};
364    /// use std::any::TypeId;
365    ///
366    /// let mut body = DynSegment::new::<()>();
367    /// body.push_arg::<i32>(0);
368    /// body.push_arg::<i32>(1);
369    /// body.op2(|a: i32, b: i32| a + b).unwrap();
370    ///
371    /// let closure = DynClosure::new(
372    ///     vec![TypeId::of::<i32>(), TypeId::of::<i32>()],
373    ///     TypeId::of::<i32>(),
374    ///     body,
375    /// );
376    /// assert_eq!(closure.param_types().len(), 2);
377    /// ```
378    #[must_use]
379    pub fn new(param_types: Vec<TypeId>, return_type: TypeId, body: DynSegment) -> Self {
380        DynClosure(
381            Rc::new(ClosureData {
382                param_types,
383                return_type,
384                body: RefCell::new(ClosureBody::Interpreted(body)),
385                frame: None,
386                signature: None,
387                trusted_bindings: Cell::new(0),
388            }),
389            None,
390        )
391    }
392
393    /// Wraps a checked CEL body while retaining its full callable shape.
394    ///
395    /// # Errors
396    /// Returns an error if the body does not produce exactly one value, requires preloaded
397    /// arguments or a nonzero ambient stack origin, reads an undeclared or differently shaped
398    /// argument, or reads a tuple whose leaves lack clone adapters. A zero-origin fragment is
399    /// valid because its operations can access only its local operands and declared arguments.
400    ///
401    /// - Complexity: O(number of parameters plus recursive nodes in body argument reads/result).
402    ///
403    /// # Examples
404    /// ```
405    /// use cel_runtime::{DynClosure, DynSegment, ValueType};
406    /// let mut body = DynSegment::new::<()>();
407    /// body.just(42i32);
408    /// let closure = DynClosure::typed(vec![], body).unwrap();
409    /// assert_eq!(closure.call::<i32>(&[]).unwrap(), 42);
410    /// ```
411    pub fn typed(parameters: Vec<ValueType>, body: DynSegment) -> anyhow::Result<Self> {
412        let result = Self::validate_body(&parameters, &body)?;
413        let tuple = ValueType::tuple(
414            parameters
415                .iter()
416                .map(|value_type| crate::AssociatedType {
417                    offset: 0,
418                    value_type: value_type.clone(),
419                })
420                .collect(),
421        )?;
422        let frame = FramePlan {
423            offsets: tuple
424                .tuple_elements()
425                .unwrap()
426                .iter()
427                .map(|f| f.offset)
428                .collect(),
429            result: crate::container_execution::ResultPlan::new(0, result.clone())?,
430        };
431        let param_types = parameters.iter().map(ValueType::type_id).collect();
432        Ok(Self(
433            Rc::new(ClosureData {
434                param_types,
435                return_type: result.type_id(),
436                signature: Some(std::sync::Arc::new(ClosureSignature { parameters, result })),
437                body: RefCell::new(ClosureBody::Interpreted(body)),
438                frame: Some(frame),
439                trusted_bindings: Cell::new(0),
440            }),
441            None,
442        ))
443    }
444
445    /// Returns a carrier whose clones retain a trusted freeze for their own lifetime.
446    ///
447    /// # Errors
448    /// Rejects an executing body or an unrepresentable additional lease.
449    pub(crate) fn bind_canonical(mut self) -> anyhow::Result<Self> {
450        if self.1.is_none() {
451            self.1 = Some(Rc::new(self.freeze_trusted_binding()?));
452        }
453        Ok(self)
454    }
455
456    /// Freezes arbitrary mutable body access across all aliases until the returned lease drops.
457    ///
458    /// This does not validate the signature; preparation must do so before binding.
459    /// Existing nonmutating execution paths remain available while leased.
460    ///
461    /// # Errors
462    /// Rejects a mutably borrowed body (including an active mutable dispatcher)
463    /// or an unrepresentable additional lease count without changing the counter.
464    pub(crate) fn freeze_trusted_binding(&self) -> anyhow::Result<TrustedBindingLease> {
465        let _body = self
466            .0
467            .body
468            .try_borrow()
469            .map_err(|_| anyhow::anyhow!("closure body is already executing"))?;
470        let count = self
471            .0
472            .trusted_bindings
473            .get()
474            .checked_add(1)
475            .ok_or_else(|| anyhow::anyhow!("too many trusted bindings"))?;
476        let lease = TrustedBindingLease {
477            closure: self.clone(),
478        };
479        self.0.trusted_bindings.set(count);
480        Ok(lease)
481    }
482
483    /// Validates independent execution and declared argument reads, returning the actual result.
484    ///
485    /// # Errors
486    /// Rejects non-single results, dependent bodies, undeclared or mismatched reads,
487    /// and tuple reads without clone adapters.
488    /// - Complexity: O(recursive nodes in body argument reads and result).
489    fn validate_body(parameters: &[ValueType], body: &DynSegment) -> anyhow::Result<ValueType> {
490        anyhow::ensure!(
491            body.stack_ids.len() == 1,
492            "closure body must produce exactly one value"
493        );
494        body.validate_independent_body()?;
495        for (index, read_type) in &body.argument_reads {
496            anyhow::ensure!(
497                parameters
498                    .get(*index)
499                    .is_some_and(|expected| expected.same_shape(read_type)),
500                "closure body argument {index} differs from its declared signature"
501            );
502            read_type.validate_clone()?;
503        }
504        Ok(body.peek_stack_infos(1)[0].value_type.clone())
505    }
506
507    /// Checks the current mutable body against its retained typed signature during preparation.
508    ///
509    /// An external mutable dispatcher may have replaced the body without updating its metadata.
510    ///
511    /// # Errors
512    /// Rejects unavailable signatures, an executing body, invalid independent bodies
513    /// or argument reads, and a result differing from the retained signature.
514    /// - Complexity: O(recursive nodes in body argument reads and result).
515    pub(crate) fn validate_body_signature(&self) -> anyhow::Result<()> {
516        let signature = self
517            .0
518            .signature
519            .as_ref()
520            .ok_or_else(|| anyhow::anyhow!("closure signature metadata is unavailable"))?;
521        let body = self
522            .0
523            .body
524            .try_borrow()
525            .map_err(|_| anyhow::anyhow!("closure body is already executing"))?;
526        let ClosureBody::Interpreted(body) = &*body else {
527            return Ok(());
528        };
529        let result = Self::validate_body(&signature.parameters, body)?;
530        anyhow::ensure!(
531            signature.result.same_shape(&result),
532            "closure body result differs from its declared signature"
533        );
534        Ok(())
535    }
536
537    /// Returns the metadata retained for a typed CEL closure.
538    pub(crate) fn signature(&self) -> Option<std::sync::Arc<ClosureSignature>> {
539        self.0.signature.clone()
540    }
541
542    /// Enriches a complete canonical signature with explicitly supplied leaf factories.
543    ///
544    /// `leaf` looks up descriptors built while each concrete Rust type was
545    /// known; a `TypeId` never synthesizes a Rust monomorphization.
546    /// Factory capabilities remain independent of identity. This changes metadata
547    /// only; [`Self::value_type`] needs no factories for the existing complete signature.
548    ///
549    /// # Errors
550    ///
551    /// Returns an error for an untyped closure (including [`Self::new`]), an
552    /// unknown nested callable signature, a missing or mismatched concrete leaf
553    /// factory, or an unrepresentable canonical tuple layout.
554    ///
555    /// - Complexity: O(n) traversal time and output space for n signature nodes,
556    ///   excluding leaf factory costs.
557    ///
558    /// # Examples
559    ///
560    /// ```
561    /// use cel_runtime::{DynClosure, DynSegment, value_type::{ValueKind, ValueType}};
562    /// use std::any::TypeId;
563    /// let mut body = DynSegment::new::<()>();
564    /// body.just(42i32);
565    /// let closure = DynClosure::typed(vec![], body).unwrap();
566    /// let complete = closure.complete_value_type(|id| {
567    ///     (id == TypeId::of::<i32>()).then(ValueType::cloneable_leaf::<i32>)
568    /// }).unwrap();
569    /// assert!(matches!(complete.kind(), ValueKind::Callable { .. }));
570    /// ```
571    pub fn complete_value_type(
572        &self,
573        mut leaf: impl FnMut(TypeId) -> Option<crate::value_type::ValueType>,
574    ) -> anyhow::Result<crate::value_type::ValueType> {
575        self.0
576            .signature
577            .as_ref()
578            .ok_or_else(|| anyhow::anyhow!("closure signature metadata is unavailable"))?
579            .complete(&mut leaf)
580    }
581
582    /// Evaluates a previously checked borrowed raw argument frame into an independent stack.
583    ///
584    /// # Safety
585    /// Every pointer must reference a live value matching `expected.parameters`, in order,
586    /// until execution returns. No pointer may be retained by an operation.
587    ///
588    /// # Errors
589    /// Returns signature mismatch, reentrant body borrow, or body evaluation errors.
590    /// - Complexity: body-dependent.
591    #[cfg(test)]
592    pub(crate) unsafe fn call_raw(
593        &self,
594        expected: &ClosureSignature,
595        arguments: &[*const u8],
596    ) -> anyhow::Result<crate::raw_stack::RawStack> {
597        debug_assert_eq!(expected.parameters.len(), arguments.len());
598        anyhow::ensure!(
599            same_signature(self.0.signature.as_deref(), Some(expected)),
600            "closure signature mismatch"
601        );
602        let mut body = self
603            .0
604            .body
605            .try_borrow_mut()
606            .map_err(|_| anyhow::anyhow!("closure body is already executing"))?;
607        unsafe { body.segment()?.execute_raw(arguments) }
608    }
609
610    /// Executes this carrier with a construction-validated, representation-matched frame.
611    ///
612    /// This path deliberately omits the external signature check. The prepared
613    /// invocation owns a clone of this exact carrier, preventing substitution.
614    ///
615    /// # Safety
616    ///
617    /// Preparation must validate the actual body's independent origin, argument reads,
618    /// and result against this closure's full signature and its canonical physical
619    /// frame. Every pointer must remain a live matching borrowed value
620    /// until execution returns; operations must not retain argument pointers.
621    /// A trusted-binding lease must protect the validated body from modification
622    /// throughout preparation and execution.
623    ///
624    /// # Errors
625    ///
626    /// Returns reentrant body borrow or body evaluation errors.
627    /// - Complexity: Body-dependent time and independent evaluation stack storage.
628    #[cfg(test)]
629    pub(crate) unsafe fn call_raw_trusted(
630        &self,
631        arguments: &[*const u8],
632    ) -> anyhow::Result<crate::raw_stack::RawStack> {
633        debug_assert_eq!(arguments.len(), self.0.param_types.len());
634        debug_assert!(self.0.signature.is_some());
635        let mut body = self
636            .0
637            .body
638            .try_borrow_mut()
639            .map_err(|_| anyhow::anyhow!("closure body is already executing"))?;
640        unsafe { body.segment()?.execute_raw(arguments) }
641    }
642
643    /// Returns this closure's declared parameter types, in order.
644    ///
645    /// # Examples
646    ///
647    /// ```rust
648    /// use cel_runtime::{DynClosure, DynSegment};
649    /// use std::any::TypeId;
650    ///
651    /// let mut body = DynSegment::new::<()>();
652    /// body.push_arg::<i32>(0);
653    /// body.push_arg::<i32>(1);
654    /// body.op2(|a: i32, b: i32| a + b).unwrap();
655    ///
656    /// let closure = DynClosure::new(
657    ///     vec![TypeId::of::<i32>(), TypeId::of::<i32>()],
658    ///     TypeId::of::<i32>(),
659    ///     body,
660    /// );
661    /// assert_eq!(closure.param_types(), &[TypeId::of::<i32>(), TypeId::of::<i32>()]);
662    /// ```
663    #[must_use]
664    pub fn param_types(&self) -> &[TypeId] {
665        &self.0.param_types
666    }
667
668    /// Returns this closure's declared return type.
669    ///
670    /// # Examples
671    ///
672    /// ```rust
673    /// use cel_runtime::{DynClosure, DynSegment};
674    /// use std::any::TypeId;
675    ///
676    /// let mut body = DynSegment::new::<()>();
677    /// body.push_arg::<i32>(0);
678    /// body.push_arg::<i32>(1);
679    /// body.op2(|a: i32, b: i32| a + b).unwrap();
680    ///
681    /// let closure = DynClosure::new(
682    ///     vec![TypeId::of::<i32>(), TypeId::of::<i32>()],
683    ///     TypeId::of::<i32>(),
684    ///     body,
685    /// );
686    /// assert_eq!(closure.return_type(), TypeId::of::<i32>());
687    /// ```
688    #[must_use]
689    pub fn return_type(&self) -> TypeId {
690        self.0.return_type
691    }
692
693    /// Invokes the closure's body with `args`, positionally matched against `param_types`.
694    ///
695    /// - Precondition: `args.len() == self.param_types().len()` and each `args[i]`'s runtime type
696    ///   matches `param_types()[i]` — the caller (adam-lang's generated `Filter` wrapper, or any
697    ///   future caller) must guarantee this ahead of time; a violation is a caller bug, not user
698    ///   error (matches `DynSegment::push_arg`'s own existing precondition, which this delegates
699    ///   to unchanged).
700    /// - Precondition: `TypeId::of::<R>() == self.return_type()`.
701    /// - Complexity: whatever the body's own evaluation complexity is.
702    ///
703    /// # Examples
704    ///
705    /// ```rust
706    /// use cel_runtime::{DynClosure, DynSegment};
707    /// use std::any::TypeId;
708    ///
709    /// let mut body = DynSegment::new::<()>();
710    /// body.push_arg::<i32>(0);
711    /// body.push_arg::<i32>(1);
712    /// body.op2(|a: i32, b: i32| a + b).unwrap();
713    ///
714    /// let closure = DynClosure::new(
715    ///     vec![TypeId::of::<i32>(), TypeId::of::<i32>()],
716    ///     TypeId::of::<i32>(),
717    ///     body,
718    /// );
719    /// let (a, b) = (2i32, 3i32);
720    /// let result: i32 = closure.call(&[&a, &b]).unwrap();
721    /// assert_eq!(result, 5);
722    /// ```
723    pub fn call<R: 'static>(&self, args: &[&dyn Any]) -> anyhow::Result<R> {
724        debug_assert_eq!(args.len(), self.0.param_types.len());
725        self.0
726            .body
727            .try_borrow_mut()
728            .map_err(|_| anyhow::anyhow!("closure body is already executing"))?
729            .segment()?
730            .call_dyn::<R>(args)
731    }
732
733    /// Invokes the closure's body with `args`, like [`call`](Self::call), for a caller that only
734    /// knows the return type dynamically (as a `TypeId`) rather than as a static Rust generic —
735    /// `call_dyn_fn` is a monomorphized dispatcher the caller already has for that type (e.g.
736    /// `adam-lang`'s per-type `TypeRegistry::TypeEntry::call_dyn_fn`).
737    ///
738    /// - Precondition: `args.len() == self.param_types().len()` and each `args[i]`'s runtime type
739    ///   matches `param_types()[i]`, exactly as for [`call`](Self::call).
740    /// - Precondition: `call_dyn_fn` is a dispatcher for `self.return_type()` (i.e. it calls
741    ///   `DynSegment::call_dyn::<R>` for the same concrete `R` that `TypeId` names).
742    /// - Complexity: whatever the body's own evaluation complexity is.
743    ///
744    /// # Errors
745    ///
746    /// Returns an error without invoking `call_dyn_fn` while any trusted binding
747    /// leases this shared body, including through another clone. Mutable dispatch
748    /// resumes after the last lease drops. Otherwise propagates dispatcher errors.
749    ///
750    /// # Examples
751    ///
752    /// ```rust
753    /// use cel_runtime::{DynClosure, DynSegment};
754    /// use std::any::{Any, TypeId};
755    ///
756    /// let mut body = DynSegment::new::<()>();
757    /// body.push_arg::<i32>(0);
758    /// body.push_arg::<i32>(1);
759    /// body.op2(|a: i32, b: i32| a + b).unwrap();
760    ///
761    /// let closure = DynClosure::new(
762    ///     vec![TypeId::of::<i32>(), TypeId::of::<i32>()],
763    ///     TypeId::of::<i32>(),
764    ///     body,
765    /// );
766    ///
767    /// fn dispatch_i32(seg: &mut DynSegment, inputs: &[&dyn Any]) -> anyhow::Result<Box<dyn Any>> {
768    ///     let result: i32 = seg.call_dyn(inputs)?;
769    ///     Ok(Box::new(result))
770    /// }
771    ///
772    /// let (a, b) = (4i32, 5i32);
773    /// let result = closure.call_boxed(&[&a, &b], dispatch_i32).unwrap();
774    /// assert_eq!(*result.downcast_ref::<i32>().unwrap(), 9);
775    /// ```
776    pub fn call_boxed(
777        &self,
778        args: &[&dyn Any],
779        call_dyn_fn: CallDynFn,
780    ) -> anyhow::Result<Box<dyn Any>> {
781        debug_assert_eq!(args.len(), self.0.param_types.len());
782        anyhow::ensure!(
783            self.0.trusted_bindings.get() == 0,
784            "closure body is frozen by a trusted binding"
785        );
786        let mut body = self
787            .0
788            .body
789            .try_borrow_mut()
790            .map_err(|_| anyhow::anyhow!("closure body is already executing"))?;
791        call_dyn_fn(body.segment()?, args)
792    }
793}
794
795#[cfg(test)]
796mod tests {
797    use super::*;
798    use crate::dyn_segment::DynSegment;
799
800    /// Clones and drops the existing shared carrier without erasing its signature.
801    #[test]
802    fn complete_factory_callable_owns_shared_carrier() {
803        use crate::value_type::ValueType as Complete;
804        use std::mem::{ManuallyDrop, MaybeUninit};
805        let mut body = DynSegment::new::<()>();
806        body.just(42i32);
807        let closure = DynClosure::typed(vec![], body).unwrap();
808        let weak = Rc::downgrade(&closure.0);
809        let descriptor = Complete::callable(vec![], Complete::leaf::<i32>());
810        assert_eq!(descriptor.layout(), std::alloc::Layout::new::<DynClosure>());
811        assert!(descriptor.can_clone());
812        assert!(descriptor.can_debug());
813        assert!(!descriptor.can_compare());
814        let mut source = ManuallyDrop::new(closure);
815        let source_ptr = (&mut *source as *mut DynClosure).cast::<u8>();
816        let mut destination = MaybeUninit::<DynClosure>::uninit();
817        // SAFETY: Both locations have the statically known carrier layout and
818        // the descriptor describes this closure's signature.
819        unsafe {
820            crate::owned_value::clone_raw(&descriptor, source_ptr, destination.as_mut_ptr().cast());
821            crate::owned_value::drop_raw(&descriptor, source_ptr);
822            assert!(weak.upgrade().is_some());
823            assert_eq!(destination.assume_init_ref().call::<i32>(&[]).unwrap(), 42);
824            crate::owned_value::drop_raw(&descriptor, destination.as_mut_ptr().cast());
825        }
826        assert!(weak.upgrade().is_none());
827    }
828
829    /// Keeps tuple and array identities in migrated signatures.
830    #[test]
831    fn complete_factory_preserves_structural_callable_signatures() {
832        use crate::value_type::{ValueKind, ValueType as Complete};
833        let mut body = DynSegment::new::<()>();
834        body.just(1i32);
835        body.make_tuple(1, 0).unwrap();
836        let parameter = ValueType::array(ValueType::cloneable_leaf::<i32>());
837        let closure = DynClosure::typed(vec![parameter], body).unwrap();
838        let descriptor = closure
839            .complete_value_type(|id| {
840                (id == TypeId::of::<i32>()).then(Complete::cloneable_leaf::<i32>)
841            })
842            .unwrap();
843        let ValueKind::Callable { parameters, result } = descriptor.kind() else {
844            panic!("expected complete callable metadata");
845        };
846        assert!(parameters[0].same_shape(&Complete::array(Complete::leaf::<i32>())));
847        assert!(!parameters[0].same_shape(&Complete::array(Complete::leaf::<u32>())));
848        assert!(matches!(result.kind(), ValueKind::Tuple(fields) if fields.len() == 1));
849        assert!(!result.same_shape(&Complete::leaf::<i32>()));
850        assert!(!descriptor.same_shape(&Complete::callable(
851            vec![Complete::array(Complete::leaf::<u32>())],
852            (**result).clone()
853        )));
854        assert!(!descriptor.same_shape(&Complete::callable(
855            parameters.clone(),
856            Complete::leaf::<i32>()
857        )));
858    }
859
860    /// Retains known nested callable results and distinguishes canonical source unit.
861    #[test]
862    fn complete_factory_preserves_nested_callable_and_unit() {
863        use crate::value_type::{Nil, ValueKind, ValueRepr, ValueType as Complete};
864        let mut inner_body = DynSegment::new::<()>();
865        inner_body.make_tuple(0, 0).unwrap();
866        let inner = DynClosure::typed(vec![ValueType::leaf::<()>()], inner_body).unwrap();
867        let mut body = DynSegment::new::<()>();
868        body.push_closure(inner).unwrap();
869        let outer = DynClosure::typed(vec![], body).unwrap();
870        let complete = outer
871            .complete_value_type(|id| (id == TypeId::of::<()>()).then(Complete::leaf::<()>))
872            .unwrap();
873        let ValueKind::Callable { result, .. } = complete.kind() else {
874            panic!("expected callable");
875        };
876        let ValueKind::Callable { parameters, result } = result.kind() else {
877            panic!("expected nested callable");
878        };
879        assert!(parameters[0].same_shape(&Complete::leaf::<()>()));
880        assert!(!parameters[0].same_shape(&Nil::value_type()));
881        assert!(result.same_shape(&Nil::value_type()));
882        assert!(!result.same_shape(&Complete::leaf::<()>()));
883    }
884
885    /// Rejects unavailable signatures and missing or incorrectly keyed leaf factories.
886    #[test]
887    fn complete_factory_rejects_unknown_callable_metadata() {
888        use crate::value_type::ValueType as Complete;
889        assert!(
890            adder_closure()
891                .complete_value_type(|_| Some(Complete::leaf::<i32>()))
892                .is_err()
893        );
894        let mut body = DynSegment::new::<()>();
895        body.just(1i32);
896        let closure = DynClosure::typed(vec![], body).unwrap();
897        assert!(closure.complete_value_type(|_| None).is_err());
898        assert!(
899            closure
900                .complete_value_type(|_| Some(Complete::leaf::<u32>()))
901                .is_err()
902        );
903        assert!(
904            closure
905                .complete_value_type(|_| Some(Complete::array(Complete::leaf::<i32>())))
906                .is_err()
907        );
908
909        let mut body = DynSegment::new::<()>();
910        body.just(adder_closure());
911        let closure = DynClosure::typed(vec![], body).unwrap();
912        assert!(
913            closure
914                .complete_value_type(|_| Some(Complete::leaf::<DynClosure>()))
915                .is_err()
916        );
917    }
918
919    fn adder_closure() -> DynClosure {
920        let mut body = DynSegment::new::<()>();
921        body.push_arg::<i32>(0);
922        body.push_arg::<i32>(1);
923        body.op2(|a: i32, b: i32| a + b).unwrap();
924        DynClosure::new(
925            vec![TypeId::of::<i32>(), TypeId::of::<i32>()],
926            TypeId::of::<i32>(),
927            body,
928        )
929    }
930
931    #[test]
932    fn call_invokes_body_with_positional_args() {
933        let closure = adder_closure();
934        let (a, b) = (2i32, 3i32);
935        let result: i32 = closure.call(&[&a, &b]).unwrap();
936        assert_eq!(result, 5);
937    }
938
939    #[test]
940    fn call_is_repeatable_with_different_args() {
941        let closure = adder_closure();
942        let (a1, b1) = (2i32, 3i32);
943        assert_eq!(closure.call::<i32>(&[&a1, &b1]).unwrap(), 5);
944        let (a2, b2) = (10i32, 20i32);
945        assert_eq!(closure.call::<i32>(&[&a2, &b2]).unwrap(), 30);
946    }
947
948    #[test]
949    fn clone_shares_the_same_body_and_both_remain_callable() {
950        let closure = adder_closure();
951        let cloned = closure.clone();
952        let (a, b) = (1i32, 1i32);
953        assert_eq!(closure.call::<i32>(&[&a, &b]).unwrap(), 2);
954        assert_eq!(cloned.call::<i32>(&[&a, &b]).unwrap(), 2);
955    }
956
957    #[test]
958    fn call_boxed_dispatches_through_a_supplied_call_dyn_fn() {
959        let closure = adder_closure();
960        fn call_dyn_fn(seg: &mut DynSegment, inputs: &[&dyn Any]) -> anyhow::Result<Box<dyn Any>> {
961            let v: i32 = seg.call_dyn(inputs)?;
962            Ok(Box::new(v))
963        }
964        let (a, b) = (4i32, 5i32);
965        let result = closure.call_boxed(&[&a, &b], call_dyn_fn).unwrap();
966        assert_eq!(*result.downcast_ref::<i32>().unwrap(), 9);
967    }
968
969    #[test]
970    fn param_types_and_return_type_are_queryable() {
971        let closure = adder_closure();
972        assert_eq!(
973            closure.param_types(),
974            &[TypeId::of::<i32>(), TypeId::of::<i32>()]
975        );
976        assert_eq!(closure.return_type(), TypeId::of::<i32>());
977    }
978
979    /// A typed body cannot reinterpret an argument through a different Rust representation.
980    #[test]
981    fn typed_rejects_incompatible_body_argument_reads() {
982        let mut body = DynSegment::new::<()>();
983        body.push_arg::<String>(0);
984        assert!(DynClosure::typed(vec![ValueType::leaf::<i32>()], body).is_err());
985    }
986
987    /// An undeclared positional argument cannot enter a typed raw call frame.
988    #[test]
989    fn typed_rejects_undeclared_body_argument_reads() {
990        let mut body = DynSegment::new::<()>();
991        body.push_arg::<i32>(1);
992        assert!(DynClosure::typed(vec![ValueType::leaf::<i32>()], body).is_err());
993    }
994
995    /// A shifted fragment cannot become a body evaluated on an empty stack.
996    #[test]
997    fn typed_rejects_ambient_dependent_body_without_execution() {
998        let mut inner = DynSegment::new::<()>();
999        inner.just(42i32);
1000        let closure = DynClosure::typed(vec![], inner).unwrap();
1001        let mut parent = DynSegment::new::<()>();
1002        parent.just(7u64);
1003        parent.just(true);
1004        let mut fragment = parent.new_fragment();
1005        fragment.push_closure(closure).unwrap();
1006        fragment.invoke_closure(0).unwrap();
1007
1008        assert!(DynClosure::typed(vec![], fragment).is_err());
1009    }
1010
1011    /// A zero-origin fragment contains only its local operands, even above ambient unit values.
1012    #[test]
1013    fn typed_accepts_zero_origin_body_with_nested_invocation() {
1014        let mut inner = DynSegment::new::<()>();
1015        inner.just(42i32);
1016        let closure = DynClosure::typed(vec![], inner).unwrap();
1017        let mut parent = DynSegment::new::<()>();
1018        parent.just(());
1019        parent.just(true);
1020        let mut fragment = parent.new_fragment();
1021        fragment.push_closure(closure).unwrap();
1022        fragment.invoke_closure(0).unwrap();
1023
1024        let closure = DynClosure::typed(vec![], fragment).unwrap();
1025        assert_eq!(closure.call::<i32>(&[]).unwrap(), 42);
1026        let mut caller = DynSegment::new::<()>();
1027        caller.push_closure(closure).unwrap();
1028        caller.invoke_closure(0).unwrap();
1029        assert_eq!(caller.call0::<i32>().unwrap(), 42);
1030    }
1031
1032    /// A root body cannot hide a shifted fragment behind a conditional join.
1033    #[test]
1034    fn typed_body_join_rejects_mismatched_fragment_origins_without_execution() {
1035        for shifted_first in [true, false] {
1036            let mut parent = DynSegment::new::<()>();
1037            parent.just(7u64);
1038            parent.just(true);
1039            let mut shifted = parent.new_fragment();
1040            shifted.just(42i32);
1041            let mut body = DynSegment::new::<()>();
1042            body.just(true);
1043            let mut alternate = body.new_fragment();
1044            alternate.just(0i32);
1045
1046            let result = if shifted_first {
1047                body.join2(shifted, alternate)
1048            } else {
1049                body.join2(alternate, shifted)
1050            };
1051            assert!(result.is_err());
1052        }
1053    }
1054
1055    /// A runtime closure value cannot masquerade as another known callable signature.
1056    #[test]
1057    fn invocation_checks_runtime_signature_before_body_execution() {
1058        let mut expected_body = DynSegment::new::<()>();
1059        expected_body.just(1i32);
1060        let expected = DynClosure::typed(vec![], expected_body).unwrap();
1061        let executed = Rc::new(std::cell::Cell::new(false));
1062        let observed = executed.clone();
1063        let mut actual_body = DynSegment::new::<()>();
1064        actual_body.op0(move || {
1065            observed.set(true);
1066            true
1067        });
1068        let actual = DynClosure::typed(vec![], actual_body).unwrap();
1069        // Both signatures have no parameters, so the borrowed argument frame is valid.
1070        let error = unsafe { actual.call_raw(&expected.signature().unwrap(), &[]) }.unwrap_err();
1071        assert!(error.to_string().contains("signature mismatch"));
1072        assert!(!executed.get());
1073    }
1074
1075    /// Argument reads inside alternate fragments participate in signature validation.
1076    #[test]
1077    fn typed_checks_conditional_argument_reads() {
1078        let mut body = DynSegment::new::<()>();
1079        body.just(true);
1080        let mut then_branch = body.new_fragment();
1081        then_branch.push_arg::<String>(0);
1082        let mut else_branch = body.new_fragment();
1083        else_branch.just(String::new());
1084        body.join2(then_branch, else_branch).unwrap();
1085        assert!(DynClosure::typed(vec![ValueType::leaf::<i32>()], body).is_err());
1086    }
1087
1088    /// Rejected invocation leaves the evaluated operand descriptors and operations unchanged.
1089    #[test]
1090    fn wrong_argument_type_is_rejected_before_emitting() {
1091        let mut body = DynSegment::new::<()>();
1092        body.push_arg::<i32>(0);
1093        let closure = DynClosure::typed(vec![ValueType::leaf::<i32>()], body).unwrap();
1094        let mut caller = DynSegment::new::<()>();
1095        caller.push_closure(closure).unwrap();
1096        caller.just(false);
1097        assert!(caller.invoke_closure(1).is_err());
1098        assert_eq!(caller.peek_stack_infos(2).len(), 2);
1099        caller.op1(|_: bool| 8i32).unwrap();
1100        caller.invoke_closure(1).unwrap();
1101        assert_eq!(caller.call0::<i32>().unwrap(), 8);
1102    }
1103
1104    /// Preloaded Rust argument layouts cannot enter the positional CEL invocation adapter.
1105    #[test]
1106    fn preloaded_arguments_fail_explicitly() {
1107        let mut body = DynSegment::new::<()>();
1108        body.just(1i32);
1109        let mut caller = DynSegment::new::<(i32,)>();
1110        caller
1111            .push_closure(DynClosure::typed(vec![], body).unwrap())
1112            .unwrap();
1113        assert!(caller.invoke_closure(0).is_err());
1114    }
1115}