cel_runtime/value_type.rs
1//! Describes complete recursive identities independently of interpreter descriptors.
2//!
3//! Witnesses name concrete Rust representations without requiring foreign types
4//! to implement a trait. Capability adapters are optional and checked separately:
5//!
6//! ```
7//! use cel_runtime::value_type::{ArrayOf, Leaf, ValueRepr, ValueType};
8//! let array = ValueType::array(ValueType::cloneable_leaf::<String>());
9//! assert!(array.same_shape(&ArrayOf::<Leaf<String>>::value_type()));
10//! ```
11
12use std::alloc::Layout;
13use std::any::TypeId;
14use std::fmt::{Debug, Write};
15use std::marker::PhantomData;
16use std::sync::Arc;
17
18use crate::array::RawArray;
19use crate::c_stack_list::CStackListHeadLimit;
20use crate::tuple_value::TupleLayout;
21use crate::{Array, CNil, CStackList};
22
23#[cfg(test)]
24thread_local! {
25 /// Counts descriptor comparisons on this test thread, including recursive calls.
26 pub(crate) static SHAPE_COMPARISONS: std::cell::Cell<usize> = const {
27 std::cell::Cell::new(0)
28 };
29}
30
31/// Seals representation witnesses and limits list tails to canonical lists.
32mod sealed {
33 use super::{AssociatedType, ValueRepr};
34
35 /// Prevents downstream implementations from inventing unsafe representations.
36 pub trait Sealed {}
37
38 /// Supplies source-ordered fields only for canonical list witnesses.
39 pub trait List: ValueRepr {
40 /// Appends this list's source-ordered fields.
41 ///
42 /// - Complexity: O(n) time and space for n fields.
43 fn fields(fields: &mut Vec<AssociatedType>);
44 }
45}
46
47/// Names a trusted concrete representation without wrapping its runtime value.
48///
49/// Only this crate implements the trait; use [`Leaf`] for any foreign host type.
50///
51/// # Examples
52///
53/// ```
54/// use cel_runtime::value_type::{ArrayOf, Leaf, ValueRepr};
55/// use cel_runtime::Array;
56/// let _: <ArrayOf<Leaf<i32>> as ValueRepr>::Value = Array::from_vec(vec![1]);
57/// ```
58pub trait ValueRepr: sealed::Sealed {
59 /// The concrete, owned Rust representation.
60 type Value: 'static;
61
62 /// Returns the complete identity, layout, and ownership plan.
63 ///
64 /// Leaves have no optional capabilities by default.
65 ///
66 /// - Complexity: O(n) time and space for n nodes in the descriptor tree.
67 ///
68 /// # Examples
69 ///
70 /// ```
71 /// use cel_runtime::value_type::{Leaf, ValueRepr, ValueType};
72 /// assert!(Leaf::<i32>::value_type().same_shape(&ValueType::leaf::<i32>()));
73 /// ```
74 fn value_type() -> ValueType;
75}
76
77/// Names an opaque host leaf of type `T`, including explicitly registered `()`.
78///
79/// Aggregate-looking host types remain opaque when explicitly named as leaves.
80///
81/// # Examples
82///
83/// ```
84/// use cel_runtime::value_type::{Leaf, ValueRepr};
85/// let _: <Leaf<String> as ValueRepr>::Value = String::new();
86/// ```
87pub struct Leaf<T>(PhantomData<fn() -> T>);
88
89/// Names a homogeneous array whose elements use witness `E`.
90///
91/// # Examples
92///
93/// ```
94/// use cel_runtime::value_type::{ArrayOf, Leaf, ValueRepr};
95/// use cel_runtime::Array;
96/// let _: <ArrayOf<Leaf<u8>> as ValueRepr>::Value = Array::from_vec(vec![1]);
97/// ```
98pub struct ArrayOf<E>(PhantomData<fn() -> E>);
99
100/// Names canonical source unit, represented by `CNil<()>`, not a host `()`.
101///
102/// # Examples
103///
104/// ```
105/// use cel_runtime::{IntoCStackList, value_type::{Nil, ValueRepr}};
106/// let _: <Nil as ValueRepr>::Value = ().into_c_stack_list();
107/// ```
108pub struct Nil;
109
110/// Names a source-first tuple head `H` followed by canonical list tail `T`.
111///
112/// # Examples
113///
114/// ```
115/// use cel_runtime::{IntoCStackList, value_type::{Cons, Leaf, Nil, ValueRepr}};
116/// let _: <Cons<Leaf<i32>, Nil> as ValueRepr>::Value = (1,).into_c_stack_list();
117/// ```
118///
119/// Noncanonical tails cannot authorize a representation:
120///
121/// ```compile_fail
122/// use cel_runtime::value_type::{Cons, Leaf, ValueRepr};
123/// let _ = Cons::<Leaf<i32>, Leaf<()>>::value_type();
124/// ```
125pub struct Cons<H, T>(PhantomData<fn() -> (H, T)>);
126
127/// Names a canonical tuple argument list, sealed to [`Nil`] and [`Cons`].
128///
129/// # Examples
130/// ```
131/// use cel_runtime::{ArgumentList, Cons, Leaf, Nil};
132/// fn list<A: ArgumentList>() {}
133/// list::<Cons<Leaf<i32>, Nil>>();
134/// ```
135pub trait ArgumentList: ValueRepr + sealed::List {}
136impl<T: sealed::List> ArgumentList for T {}
137
138/// Names a callable with a complete canonical parameter and result signature.
139///
140/// The shared carrier always clones, regardless of argument/result capabilities.
141/// Equality and default construction are not implied.
142///
143/// # Examples
144/// ```
145/// use cel_runtime::{FnOf, Nil, Leaf, ValueRepr, Callable, CNil};
146/// let _: <FnOf<Nil, Leaf<i32>> as ValueRepr>::Value =
147/// Callable::from_fn(|_: &CNil<()>| Ok(7));
148/// ```
149///
150/// Non-list arguments cannot authorize a callable representation:
151/// ```compile_fail
152/// use cel_runtime::{FnOf, Leaf, ValueRepr};
153/// let _ = FnOf::<Leaf<()>, Leaf<i32>>::value_type();
154/// ```
155pub struct FnOf<A, R>(PhantomData<fn() -> (A, R)>);
156
157impl<A: ArgumentList, R: ValueRepr> sealed::Sealed for FnOf<A, R> {}
158impl<A: ArgumentList, R: ValueRepr> ValueRepr for FnOf<A, R> {
159 type Value = crate::Callable<A::Value, R::Value>;
160
161 /// Describes every parameter and result node with canonical carrier ownership.
162 ///
163 /// - Complexity: O(n) time and storage for n signature nodes.
164 fn value_type() -> ValueType {
165 let args = A::value_type();
166 ValueType::callable(
167 args.tuple_elements()
168 .expect("sealed canonical argument list")
169 .iter()
170 .map(|field| field.value_type.clone())
171 .collect(),
172 R::value_type(),
173 )
174 }
175}
176
177impl<T: 'static> sealed::Sealed for Leaf<T> {}
178impl<T: 'static> ValueRepr for Leaf<T> {
179 /// Describes the explicitly registered opaque host representation.
180 fn value_type() -> ValueType {
181 ValueType::leaf::<T>()
182 }
183 type Value = T;
184}
185
186impl<E: ValueRepr> sealed::Sealed for ArrayOf<E> {}
187impl<E: ValueRepr> ValueRepr for ArrayOf<E> {
188 type Value = Array<E::Value>;
189 /// Describes this array and its complete concrete element representation.
190 ///
191 /// - Complexity: O(n) time and space for n element descriptor nodes.
192 fn value_type() -> ValueType {
193 ValueType::array(E::value_type())
194 }
195}
196
197impl sealed::Sealed for Nil {}
198impl ValueRepr for Nil {
199 type Value = CNil<()>;
200 /// Describes canonical source unit with its empty-list ownership plan.
201 fn value_type() -> ValueType {
202 ValueType::tuple(Vec::new()).expect("empty canonical tuple fits Layout")
203 }
204}
205impl sealed::List for Nil {
206 /// Appends no fields for canonical source unit.
207 fn fields(_: &mut Vec<AssociatedType>) {}
208}
209
210impl<H: ValueRepr, T: sealed::List> sealed::Sealed for Cons<H, T> where T::Value: CStackListHeadLimit
211{}
212impl<H: ValueRepr, T: sealed::List> ValueRepr for Cons<H, T>
213where
214 T::Value: CStackListHeadLimit,
215{
216 type Value = CStackList<H::Value, T::Value>;
217 /// Describes source-ordered fields using their canonical recursive layout.
218 ///
219 /// - Complexity: O(n) time and space for n descriptor nodes.
220 fn value_type() -> ValueType {
221 let mut fields = Vec::new();
222 <Self as sealed::List>::fields(&mut fields);
223 let descriptor = ValueType::tuple(fields).expect("concrete Rust list fits Layout");
224 debug_assert_eq!(descriptor.layout(), Layout::new::<Self::Value>());
225 descriptor
226 }
227}
228impl<H: ValueRepr, T: sealed::List> sealed::List for Cons<H, T>
229where
230 T::Value: CStackListHeadLimit,
231{
232 /// Appends the head descriptor followed by the canonical tail's descriptors.
233 ///
234 /// - Complexity: O(n) time and space for n descriptor nodes.
235 fn fields(fields: &mut Vec<AssociatedType>) {
236 fields.push(AssociatedType {
237 offset: 0,
238 value_type: H::value_type(),
239 });
240 T::fields(fields);
241 }
242}
243
244/// Identifies a value structurally, independently of aggregate storage markers.
245///
246/// Callable metadata includes every parameter and the result. Its private
247/// ownership plan uses the shared `DynClosure` carrier, exactly matching the
248/// transparent [`crate::Callable`] facade authorized by [`FnOf`].
249///
250/// # Examples
251///
252/// ```
253/// use cel_runtime::value_type::{ValueKind, ValueType};
254/// assert!(matches!(ValueType::leaf::<i32>().kind(), ValueKind::Leaf(_)));
255/// ```
256#[derive(Clone, Debug)]
257pub enum ValueKind {
258 /// A single explicitly registered opaque Rust type.
259 Leaf(TypeId),
260 /// Source-ordered fields with canonical physical offsets.
261 Tuple(Vec<AssociatedType>),
262 /// One complete homogeneous element descriptor.
263 Array(ValueType),
264 /// Complete semantic callable signature for the shared closure carrier.
265 Callable {
266 /// Parameter types in source order.
267 parameters: Vec<ValueType>,
268 /// The complete result type, including source unit or aggregates.
269 result: Box<ValueType>,
270 },
271}
272
273/// Associates a source-ordered tuple field with its canonical physical offset.
274///
275/// [`ValueType::tuple`] replaces supplied offsets; callers cannot forge layout.
276///
277/// # Examples
278///
279/// ```
280/// use cel_runtime::value_type::{AssociatedType, ValueType};
281/// let field = AssociatedType { offset: 0, value_type: ValueType::leaf::<i32>() };
282/// assert!(ValueType::tuple(vec![field]).is_ok());
283/// ```
284#[derive(Clone, Debug)]
285pub struct AssociatedType {
286 /// Byte offset relative to the enclosing canonical list.
287 pub offset: usize,
288 /// Complete field identity and ownership metadata.
289 pub value_type: ValueType,
290}
291
292/// Clones a live concrete value into aligned, disjoint uninitialized storage.
293type CloneHook = unsafe fn(*const u8, *mut u8);
294/// Compares two live values of one validated concrete representation.
295type EqualityHook = unsafe fn(*const u8, *const u8) -> bool;
296/// Formats a live value of one validated concrete representation.
297type DebugHook = unsafe fn(*const u8, &mut String);
298/// Destroys a live leaf of the registered concrete type exactly once.
299type DropHook = unsafe fn(*mut u8);
300
301/// Freezes one descriptor's ownership and independent capability plans.
302#[derive(Clone, Debug)]
303struct Plan {
304 kind: ValueKind,
305 layout: Layout,
306 leaf_drop: Option<DropHook>,
307 clone_hook: Option<CloneHook>,
308 equality_hook: Option<EqualityHook>,
309 debug_hook: Option<DebugHook>,
310 cloneable: bool,
311 comparable: bool,
312 debuggable: bool,
313 host_leaf: Option<crate::host_value_bridge::LeafBridge>,
314}
315
316/// Owns immutable recursive identity, canonical layout, and trusted operations.
317///
318/// Capabilities never change type identity. Cloning a descriptor shares its
319/// frozen plan; capability installation returns an independently updated plan.
320///
321/// # Examples
322///
323/// ```
324/// use cel_runtime::value_type::ValueType;
325/// let a = ValueType::array(ValueType::leaf::<i32>());
326/// let b = ValueType::array(ValueType::cloneable_leaf::<i32>());
327/// assert!(a.same_shape(&b));
328/// ```
329#[derive(Clone, Debug)]
330pub struct ValueType(Arc<Plan>);
331
332impl ValueType {
333 /// Sets an opaque leaf's diagnostic name without changing identity or capabilities.
334 ///
335 /// Structural descriptors retain their recursively defined names.
336 ///
337 /// # Examples
338 /// ```
339 /// let ty = cel_runtime::ValueType::leaf::<i32>().with_type_name("Integer");
340 /// assert_eq!(ty.type_name(), "Integer");
341 /// ```
342 pub fn with_type_name(mut self, name: impl Into<std::borrow::Cow<'static, str>>) -> Self {
343 if let Some(host) = Arc::make_mut(&mut self.0).host_leaf.as_mut() {
344 host.name = name.into();
345 }
346 self
347 }
348
349 /// Rejects erased whole-value owners as opaque canonical elements.
350 ///
351 /// # Errors
352 /// Rejects an `OwnedValue` leaf at any recursive node; owners require a checked whole-value boundary.
353 /// - Complexity: O(n) traversal for n descriptor nodes.
354 pub(crate) fn validate_canonical(&self) -> anyhow::Result<()> {
355 match self.kind() {
356 ValueKind::Leaf(id) => anyhow::ensure!(
357 *id != TypeId::of::<crate::OwnedValue>(),
358 "whole-value owners cannot be opaque canonical elements"
359 ),
360 ValueKind::Array(element) => element.validate_canonical()?,
361 ValueKind::Tuple(fields) => {
362 for field in fields {
363 field.value_type.validate_canonical()?;
364 }
365 }
366 ValueKind::Callable { parameters, result } => {
367 for parameter in parameters {
368 parameter.validate_canonical()?;
369 }
370 result.validate_canonical()?;
371 }
372 }
373 Ok(())
374 }
375
376 /// Returns whether the complete frozen plan supports borrowed argument cloning.
377 ///
378 /// # Examples
379 /// ```
380 /// assert!(cel_runtime::ValueType::cloneable_leaf::<i32>().can_clone_for_argument());
381 /// ```
382 pub fn can_clone_for_argument(&self) -> bool {
383 self.can_clone()
384 }
385 /// Returns a diagnostic carrier identity; structural casts require witnesses.
386 ///
387 /// # Examples
388 /// ```
389 /// assert_eq!(cel_runtime::ValueType::leaf::<i32>().type_id(), std::any::TypeId::of::<i32>());
390 /// ```
391 pub fn type_id(&self) -> TypeId {
392 match self.kind() {
393 ValueKind::Leaf(id) => *id,
394 ValueKind::Tuple(_) => TypeId::of::<crate::CNil<()>>(),
395 ValueKind::Array(_) => TypeId::of::<RawArray>(),
396 ValueKind::Callable { .. } => TypeId::of::<crate::DynClosure>(),
397 }
398 }
399
400 /// Returns a human-readable diagnostic representation name.
401 ///
402 /// # Examples
403 /// ```
404 /// assert_eq!(cel_runtime::ValueType::leaf::<i32>().type_name(), "i32");
405 /// ```
406 pub fn type_name(&self) -> &str {
407 match self.kind() {
408 ValueKind::Leaf(_) => self.host_leaf().map_or("opaque", |host| host.name()),
409 ValueKind::Tuple(_) => "canonical tuple",
410 ValueKind::Array(_) => "canonical array",
411 ValueKind::Callable { .. } => "callable",
412 }
413 }
414
415 /// Returns the canonical representation size.
416 ///
417 /// # Examples
418 /// ```
419 /// assert_eq!(cel_runtime::ValueType::leaf::<i32>().size(), 4);
420 /// ```
421 pub fn size(&self) -> usize {
422 self.layout().size()
423 }
424
425 /// Returns the canonical representation alignment.
426 ///
427 /// # Examples
428 /// ```
429 /// assert_eq!(cel_runtime::ValueType::leaf::<u8>().align(), 1);
430 /// ```
431 pub fn align(&self) -> usize {
432 self.layout().align()
433 }
434
435 /// Borrows source-ordered canonical tuple fields, including empty source unit.
436 ///
437 /// # Examples
438 /// ```
439 /// assert!(cel_runtime::ValueType::leaf::<i32>().tuple_elements().is_none());
440 /// ```
441 pub fn tuple_elements(&self) -> Option<&[AssociatedType]> {
442 match self.kind() {
443 ValueKind::Tuple(fields) => Some(fields),
444 _ => None,
445 }
446 }
447
448 /// Borrows the complete canonical array element descriptor.
449 ///
450 /// # Examples
451 /// ```
452 /// assert!(cel_runtime::ValueType::array(cel_runtime::ValueType::leaf::<i32>()).array_element().is_some());
453 /// ```
454 pub fn array_element(&self) -> Option<&ValueType> {
455 match self.kind() {
456 ValueKind::Array(element) => Some(element),
457 _ => None,
458 }
459 }
460
461 /// Registers a borrowed canonical argument read using this complete clone plan.
462 ///
463 /// # Errors
464 /// Rejects unavailable cloning or an unrepresentable destination frame.
465 /// - Complexity: O(n) registration for n existing stack slots.
466 ///
467 /// # Examples
468 /// ```
469 /// let mut body = cel_runtime::DynSegment::new::<()>();
470 /// cel_runtime::ValueType::cloneable_leaf::<i32>().push_argument(&mut body, 0).unwrap();
471 /// ```
472 pub fn push_argument(
473 &self,
474 segment: &mut crate::DynSegment,
475 index: usize,
476 ) -> anyhow::Result<()> {
477 segment.push_argument(index, self.clone())
478 }
479
480 /// Checks the borrowed whole-value clone capability.
481 ///
482 /// # Errors
483 /// Rejects a descriptor whose frozen plan cannot clone its representation.
484 pub(crate) fn validate_clone(&self) -> anyhow::Result<()> {
485 anyhow::ensure!(self.can_clone(), "argument clone capability unavailable");
486 Ok(())
487 }
488
489 /// Describes an opaque host leaf without requiring optional capabilities.
490 ///
491 /// # Examples
492 ///
493 /// ```
494 /// use cel_runtime::value_type::ValueType;
495 /// assert!(!ValueType::leaf::<i32>().same_shape(&ValueType::leaf::<u32>()));
496 /// ```
497 pub fn leaf<T: 'static>() -> Self {
498 Self(Arc::new(Plan {
499 kind: ValueKind::Leaf(TypeId::of::<T>()),
500 layout: Layout::new::<T>(),
501 leaf_drop: Some(drop_leaf::<T>),
502 clone_hook: None,
503 equality_hook: None,
504 debug_hook: None,
505 cloneable: false,
506 comparable: false,
507 debuggable: false,
508 host_leaf: Some(crate::host_value_bridge::LeafBridge::new::<T>()),
509 }))
510 }
511
512 /// Describes an opaque host leaf with cloning but no other capabilities.
513 ///
514 /// # Examples
515 ///
516 /// ```
517 /// use cel_runtime::value_type::ValueType;
518 /// let _ = ValueType::cloneable_leaf::<String>();
519 /// ```
520 pub fn cloneable_leaf<T: Clone + 'static>() -> Self {
521 Self::leaf::<T>()
522 .with_clone::<Leaf<T>>()
523 .expect("identical leaf representation")
524 }
525
526 /// Describes a known signature using the existing shared closure carrier.
527 ///
528 /// Cloning shares the compiled body, independent of parameter/result clone
529 /// capabilities. Equality is unavailable; formatting describes the carrier.
530 /// This constructor installs ownership directly from the statically known
531 /// carrier, not from an opaque leaf witness.
532 ///
533 /// - Complexity: O(1), transferring ownership of the signature.
534 ///
535 /// # Examples
536 /// ```
537 /// use cel_runtime::{ValueType, FnOf, Nil, Leaf, ValueRepr};
538 /// assert!(ValueType::callable(vec![], ValueType::leaf::<i32>())
539 /// .same_shape(&FnOf::<Nil, Leaf<i32>>::value_type()));
540 /// ```
541 pub fn callable(parameters: Vec<ValueType>, result: ValueType) -> Self {
542 Self(Arc::new(Plan {
543 kind: ValueKind::Callable {
544 parameters,
545 result: Box::new(result),
546 },
547 layout: Layout::new::<crate::DynClosure>(),
548 leaf_drop: Some(drop_leaf::<crate::DynClosure>),
549 clone_hook: Some(clone_leaf::<crate::DynClosure>),
550 equality_hook: None,
551 debug_hook: Some(debug_leaf::<crate::DynClosure>),
552 cloneable: true,
553 comparable: false,
554 debuggable: true,
555 host_leaf: None,
556 }))
557 }
558
559 /// Describes a homogeneous array using the fixed owning header.
560 ///
561 /// Recursive capabilities are present exactly when the element supports them.
562 ///
563 /// # Examples
564 ///
565 /// ```
566 /// use cel_runtime::value_type::{ArrayOf, Leaf, ValueRepr, ValueType};
567 /// assert!(ValueType::array(ValueType::leaf::<i32>())
568 /// .same_shape(&ArrayOf::<Leaf<i32>>::value_type()));
569 /// ```
570 pub fn array(element: ValueType) -> Self {
571 let cloneable = element.0.cloneable;
572 let comparable = element.0.comparable;
573 let debuggable = element.0.debuggable;
574 Self(Arc::new(Plan {
575 kind: ValueKind::Array(element),
576 layout: Layout::new::<RawArray>(),
577 leaf_drop: None,
578 clone_hook: None,
579 equality_hook: None,
580 debug_hook: None,
581 cloneable,
582 comparable,
583 debuggable,
584 host_leaf: None,
585 }))
586 }
587
588 /// Computes canonical tuple layout from source-ordered fields.
589 ///
590 /// Supplied offsets are ignored. Empty input describes canonical source unit.
591 ///
592 /// - Complexity: O(n) time and space for n immediate fields.
593 ///
594 /// # Errors
595 ///
596 /// Returns an error if the recursive padded layout exceeds [`Layout`]'s bounds.
597 ///
598 /// # Examples
599 ///
600 /// ```
601 /// use cel_runtime::value_type::{Nil, ValueRepr, ValueType};
602 /// assert!(ValueType::tuple(vec![]).unwrap().same_shape(&Nil::value_type()));
603 /// ```
604 pub fn tuple(mut elements: Vec<AssociatedType>) -> anyhow::Result<Self> {
605 let fields: Vec<_> = elements
606 .iter()
607 .map(|field| field.value_type.layout())
608 .collect();
609 let layout = TupleLayout::from_fields(&fields)?;
610 for (field, offset) in elements.iter_mut().zip(layout.offsets) {
611 field.offset = offset;
612 }
613 let cloneable = elements.iter().all(|field| field.value_type.0.cloneable);
614 let comparable = elements.iter().all(|field| field.value_type.0.comparable);
615 let debuggable = elements.iter().all(|field| field.value_type.0.debuggable);
616 Ok(Self(Arc::new(Plan {
617 kind: ValueKind::Tuple(elements),
618 layout: layout.layout,
619 leaf_drop: None,
620 clone_hook: None,
621 equality_hook: None,
622 debug_hook: None,
623 cloneable,
624 comparable,
625 debuggable,
626 host_leaf: None,
627 })))
628 }
629
630 /// Borrows the complete semantic shape without permitting mutation.
631 ///
632 /// # Examples
633 ///
634 /// ```
635 /// use cel_runtime::value_type::{Nil, ValueKind, ValueRepr};
636 /// assert!(matches!(Nil::value_type().kind(), ValueKind::Tuple(_)));
637 /// ```
638 pub fn kind(&self) -> &ValueKind {
639 &self.0.kind
640 }
641
642 /// Returns the validated complete physical layout.
643 ///
644 /// # Examples
645 ///
646 /// ```
647 /// use cel_runtime::value_type::ValueType;
648 /// assert_eq!(ValueType::leaf::<u64>().layout(), std::alloc::Layout::new::<u64>());
649 /// ```
650 pub fn layout(&self) -> Layout {
651 self.0.layout
652 }
653
654 /// Compares complete semantic identities and every physical field layout.
655 ///
656 /// Capability differences do not affect identity. Equal size and alignment
657 /// alone never authorize a cast.
658 ///
659 /// - Complexity: O(n) time and O(d) call space for n nodes and nesting depth d.
660 ///
661 /// # Examples
662 ///
663 /// ```
664 /// use cel_runtime::value_type::ValueType;
665 /// assert!(!ValueType::array(ValueType::leaf::<i32>())
666 /// .same_shape(&ValueType::array(ValueType::leaf::<u32>())));
667 /// ```
668 pub fn same_shape(&self, other: &Self) -> bool {
669 #[cfg(test)]
670 SHAPE_COMPARISONS.with(|count| count.set(count.get().saturating_add(1)));
671 self.layout() == other.layout() && same_kind(self.kind(), other.kind())
672 }
673
674 /// Checks concrete identity for a legacy conversion that names only a host leaf.
675 ///
676 /// Structural values require explicit representation witnesses, regardless
677 /// of a shared carrier ID or equal layout. This checks metadata only and
678 /// does not change the existing typed segment conversion.
679 ///
680 /// # Errors
681 ///
682 /// Returns an error for structural descriptors or a different leaf identity.
683 ///
684 /// # Examples
685 ///
686 /// ```
687 /// use std::any::TypeId;
688 /// use cel_runtime::value_type::ValueType;
689 /// assert!(ValueType::leaf::<String>()
690 /// .validate_opaque_leaf(TypeId::of::<String>()).is_ok());
691 /// assert!(ValueType::tuple(vec![]).unwrap()
692 /// .validate_opaque_leaf(TypeId::of::<()>()).is_err());
693 /// ```
694 pub fn validate_opaque_leaf(&self, type_id: TypeId) -> anyhow::Result<()> {
695 anyhow::ensure!(
696 matches!(self.kind(), ValueKind::Leaf(id) if *id == type_id),
697 "value requires a matching opaque leaf or an explicit structural witness"
698 );
699 Ok(())
700 }
701
702 /// Installs a concrete clone adapter after validating the entire witness.
703 ///
704 /// - Complexity: O(n) time and space for n descriptor nodes.
705 ///
706 /// # Errors
707 ///
708 /// Returns an error on any semantic or physical representation mismatch.
709 ///
710 /// # Examples
711 ///
712 /// ```
713 /// use cel_runtime::value_type::{Leaf, ValueType};
714 /// assert!(ValueType::leaf::<i32>().with_clone::<Leaf<i32>>().is_ok());
715 /// ```
716 pub fn with_clone<R: ValueRepr>(mut self) -> anyhow::Result<Self>
717 where
718 R::Value: Clone,
719 {
720 self.validate::<R>()?;
721 let plan = Arc::make_mut(&mut self.0);
722 plan.clone_hook = Some(clone_leaf::<R::Value>);
723 plan.cloneable = true;
724 Ok(self)
725 }
726
727 /// Installs concrete equality independently of cloning and formatting.
728 ///
729 /// - Complexity: O(n) time and space for n descriptor nodes.
730 ///
731 /// # Errors
732 ///
733 /// Returns an error on any semantic or physical representation mismatch.
734 ///
735 /// # Examples
736 ///
737 /// ```
738 /// use cel_runtime::value_type::{Leaf, ValueType};
739 /// assert!(ValueType::leaf::<i32>().with_equality::<Leaf<i32>>().is_ok());
740 /// ```
741 pub fn with_equality<R: ValueRepr>(mut self) -> anyhow::Result<Self>
742 where
743 R::Value: PartialEq,
744 {
745 self.validate::<R>()?;
746 let plan = Arc::make_mut(&mut self.0);
747 plan.equality_hook = Some(equal_leaf::<R::Value>);
748 plan.comparable = true;
749 Ok(self)
750 }
751
752 /// Installs concrete debug formatting independently of other capabilities.
753 ///
754 /// - Complexity: O(n) time and space for n descriptor nodes.
755 ///
756 /// # Errors
757 ///
758 /// Returns an error on any semantic or physical representation mismatch.
759 ///
760 /// # Examples
761 ///
762 /// ```
763 /// use cel_runtime::value_type::{Leaf, ValueType};
764 /// assert!(ValueType::leaf::<i32>().with_debug::<Leaf<i32>>().is_ok());
765 /// ```
766 pub fn with_debug<R: ValueRepr>(mut self) -> anyhow::Result<Self>
767 where
768 R::Value: Debug,
769 {
770 self.validate::<R>()?;
771 let plan = Arc::make_mut(&mut self.0);
772 plan.debug_hook = Some(debug_leaf::<R::Value>);
773 plan.debuggable = true;
774 Ok(self)
775 }
776
777 /// Validates a concrete adapter before any raw operations are installed.
778 ///
779 /// - Complexity: O(n) time and space for n witness nodes.
780 ///
781 /// # Errors
782 ///
783 /// Returns an error if the full descriptor differs from the sealed witness.
784 pub(crate) fn validate<R: ValueRepr>(&self) -> anyhow::Result<()> {
785 anyhow::ensure!(
786 self.same_shape(&R::value_type()),
787 "value representation mismatch"
788 );
789 Ok(())
790 }
791
792 /// Returns whether the frozen plan can clone every required child.
793 pub(crate) fn can_clone(&self) -> bool {
794 self.0.cloneable
795 }
796
797 /// Returns whether this complete descriptor supplies value equality.
798 ///
799 /// # Examples
800 /// ```
801 /// assert!(!cel_runtime::ValueType::leaf::<i32>().can_compare());
802 /// ```
803 pub fn can_compare(&self) -> bool {
804 self.0.comparable
805 }
806
807 /// Returns whether the frozen plan can format every required child.
808 pub(crate) fn can_debug(&self) -> bool {
809 self.0.debuggable
810 }
811
812 /// Returns the optional prevalidated whole-representation clone adapter.
813 pub(crate) fn clone_hook(&self) -> Option<CloneHook> {
814 self.0.clone_hook
815 }
816
817 /// Returns the optional prevalidated whole-representation equality adapter.
818 pub(crate) fn equality_hook(&self) -> Option<EqualityHook> {
819 self.0.equality_hook
820 }
821
822 /// Returns the optional prevalidated whole-representation formatting adapter.
823 pub(crate) fn debug_hook(&self) -> Option<DebugHook> {
824 self.0.debug_hook
825 }
826
827 /// Returns the concrete leaf or callable destructor, absent for tuples and arrays.
828 pub(crate) fn leaf_drop(&self) -> Option<DropHook> {
829 self.0.leaf_drop
830 }
831
832 /// Borrows concrete host adapters installed while the leaf type is known.
833 pub(crate) fn host_leaf(&self) -> Option<&crate::host_value_bridge::LeafBridge> {
834 self.0.host_leaf.as_ref()
835 }
836}
837
838/// Compares recursive shapes, including callable argument and result identities.
839///
840/// - Complexity: O(n) time and O(d) call space for n nodes and depth d.
841fn same_kind(left: &ValueKind, right: &ValueKind) -> bool {
842 match (left, right) {
843 (ValueKind::Leaf(a), ValueKind::Leaf(b)) => a == b,
844 (ValueKind::Array(a), ValueKind::Array(b)) => a.same_shape(b),
845 (ValueKind::Tuple(a), ValueKind::Tuple(b)) => {
846 a.len() == b.len()
847 && a.iter()
848 .zip(b)
849 .all(|(a, b)| a.offset == b.offset && a.value_type.same_shape(&b.value_type))
850 }
851 (
852 ValueKind::Callable {
853 parameters: a,
854 result: ar,
855 },
856 ValueKind::Callable {
857 parameters: b,
858 result: br,
859 },
860 ) => {
861 a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.same_shape(b)) && ar.same_shape(br)
862 }
863 _ => false,
864 }
865}
866
867/// Destroys one live leaf.
868///
869/// - Complexity: The concrete type's destructor costs apply.
870///
871/// # Safety
872///
873/// `pointer` must address an exclusively owned, aligned, live `T`.
874unsafe fn drop_leaf<T>(pointer: *mut u8) {
875 unsafe { pointer.cast::<T>().drop_in_place() };
876}
877
878/// Clones a live value into a disjoint, aligned uninitialized destination.
879///
880/// - Complexity: The concrete type's clone time and allocation costs apply.
881///
882/// # Safety
883///
884/// `source` must address a live `T`; `destination` must hold uninitialized `T`
885/// storage. On panic no destination value is initialized.
886unsafe fn clone_leaf<T: Clone>(source: *const u8, destination: *mut u8) {
887 unsafe {
888 destination
889 .cast::<T>()
890 .write((&*source.cast::<T>()).clone())
891 };
892}
893
894/// Compares two live values without taking ownership.
895///
896/// - Complexity: The concrete type's equality costs apply.
897///
898/// # Safety
899///
900/// Both pointers must address aligned live values of `T` for this call.
901unsafe fn equal_leaf<T: PartialEq>(left: *const u8, right: *const u8) -> bool {
902 unsafe { *left.cast::<T>() == *right.cast::<T>() }
903}
904
905/// Appends one live value's debug representation without taking ownership.
906///
907/// - Complexity: The concrete formatter's time and output storage costs apply.
908///
909/// # Safety
910///
911/// `pointer` must address an aligned live value of `T` for this call.
912unsafe fn debug_leaf<T: Debug>(pointer: *const u8, output: &mut String) {
913 unsafe { write!(output, "{:?}", *pointer.cast::<T>()) }
914 .expect("debug formatter writes to a string");
915}
916
917#[cfg(test)]
918mod tests {
919 use super::{ValueKind, ValueType, same_kind};
920
921 /// Rejects structural descriptors when a legacy host conversion names only a leaf.
922 #[test]
923 fn complete_factory_legacy_leaf_validation_requires_concrete_identity() {
924 use std::any::TypeId;
925 assert!(
926 ValueType::leaf::<()>()
927 .validate_opaque_leaf(TypeId::of::<()>())
928 .is_ok()
929 );
930 assert!(
931 ValueType::leaf::<i32>()
932 .validate_opaque_leaf(TypeId::of::<u32>())
933 .is_err()
934 );
935 for (structural, marker) in [
936 (
937 ValueType::tuple(vec![]).unwrap(),
938 TypeId::of::<crate::CNil<()>>(),
939 ),
940 (
941 ValueType::array(ValueType::leaf::<i32>()),
942 TypeId::of::<crate::Array<i32>>(),
943 ),
944 (
945 ValueType::callable(vec![], ValueType::leaf::<()>()),
946 TypeId::of::<crate::DynClosure>(),
947 ),
948 ] {
949 assert!(structural.validate_opaque_leaf(marker).is_err());
950 }
951 }
952
953 /// Builds semantic callable metadata without constructing an execution carrier.
954 fn signature(parameter: ValueType, result: ValueType) -> ValueKind {
955 ValueKind::Callable {
956 parameters: vec![parameter],
957 result: Box::new(result),
958 }
959 }
960
961 /// Verifies complete callable parameter and result shapes participate in identity.
962 #[test]
963 fn callable_signatures_compare_every_shape() {
964 let signature_a = signature(
965 ValueType::array(ValueType::leaf::<i32>()),
966 ValueType::tuple(vec![]).unwrap(),
967 );
968 assert!(same_kind(
969 &signature_a,
970 &signature(
971 ValueType::array(ValueType::leaf::<i32>()),
972 ValueType::tuple(vec![]).unwrap(),
973 )
974 ));
975 assert!(!same_kind(
976 &signature_a,
977 &signature(
978 ValueType::array(ValueType::leaf::<u32>()),
979 ValueType::tuple(vec![]).unwrap(),
980 )
981 ));
982 assert!(!same_kind(
983 &signature_a,
984 &signature(
985 ValueType::array(ValueType::leaf::<i32>()),
986 ValueType::leaf::<()>(),
987 )
988 ));
989 assert!(!same_kind(
990 &signature_a,
991 &ValueKind::Callable {
992 parameters: vec![],
993 result: Box::new(ValueType::tuple(vec![]).unwrap()),
994 }
995 ));
996 }
997}