cel_runtime/owned_value.rs
1//! Owns an erased whole value together with its frozen ownership descriptor.
2//!
3//! Checked host conversion validates the complete representation before moving:
4//!
5//! ```
6//! use cel_runtime::owned_value::OwnedValue;
7//! use cel_runtime::value_type::{ArrayOf, Leaf};
8//! use cel_runtime::Array;
9//! let array = Array::from_vec(vec![String::from("owned")]);
10//! let pointer = array.as_slice().as_ptr();
11//! let owner = OwnedValue::new::<ArrayOf<Leaf<String>>>(array);
12//! let array = owner.try_into_typed::<ArrayOf<Leaf<String>>>().unwrap();
13//! assert_eq!(array.as_slice().as_ptr(), pointer);
14//! ```
15
16use std::alloc::{Layout, alloc, dealloc, handle_alloc_error};
17use std::mem::MaybeUninit;
18use std::ptr::{self, NonNull};
19
20use crate::array::RawArray;
21use crate::value_type::{AssociatedType, ValueKind, ValueRepr, ValueType};
22
23#[cfg(test)]
24thread_local! {
25 /// Counts nonzero canonical owner allocations on the current test thread.
26 pub(crate) static ALLOCATIONS: std::cell::Cell<usize> = const {
27 std::cell::Cell::new(0)
28 };
29}
30
31/// Owns one aligned allocation, including an aligned dangling pointer for ZSTs.
32///
33/// This owner deallocates storage but does not destroy its contents.
34pub(crate) struct Allocation {
35 pub(crate) pointer: NonNull<u8>,
36 pub(crate) layout: Layout,
37}
38
39impl Allocation {
40 /// Allocates uninitialized storage or an aligned dangling pointer for a ZST.
41 pub(crate) fn new(layout: Layout) -> Self {
42 let pointer = if layout.size() == 0 {
43 NonNull::new(ptr::without_provenance_mut(layout.align())).unwrap()
44 } else {
45 #[cfg(test)]
46 ALLOCATIONS.with(|count| count.set(count.get() + 1));
47 // SAFETY: Layout is nonzero and valid; allocation failure aborts.
48 NonNull::new(unsafe { alloc(layout) }).unwrap_or_else(|| handle_alloc_error(layout))
49 };
50 Self { pointer, layout }
51 }
52}
53
54impl Drop for Allocation {
55 /// Releases nonzero storage after its live contents have been destroyed.
56 fn drop(&mut self) {
57 if self.layout.size() != 0 {
58 // SAFETY: This owner holds the unique allocation with this exact layout.
59 unsafe { dealloc(self.pointer.as_ptr(), self.layout) };
60 }
61 }
62}
63
64/// Owns exactly one live erased value and its complete immutable descriptor.
65///
66/// No clone, equality, formatting, or thread-safety bounds are imposed on the
67/// stored value. Consuming errors destroy the original value exactly once;
68/// borrowed capability errors leave the original value unchanged.
69///
70/// - Complexity: Destruction visits every contained value in reverse logical
71/// field/element order, using O(d) call space for nesting depth d.
72///
73/// # Examples
74///
75/// ```
76/// use cel_runtime::{owned_value::OwnedValue, value_type::Leaf};
77/// let owner = OwnedValue::new::<Leaf<String>>(String::from("hello"));
78/// assert_eq!(owner.try_into_typed::<Leaf<String>>().unwrap(), "hello");
79/// ```
80pub struct OwnedValue {
81 allocation: Allocation,
82 value_type: ValueType,
83 live: bool,
84}
85
86/// Binds recursive debug capabilities independently of a value's ownership.
87///
88/// The formatter never clones or consumes a value. Each checked formatting
89/// boundary validates the complete shape before invoking any leaf hook.
90///
91/// # Examples
92/// ```
93/// use cel_runtime::{Leaf, OwnedValue, ValueType};
94/// let value = OwnedValue::new::<Leaf<i32>>(7)
95/// .with_value_type(ValueType::leaf::<i32>().with_debug::<Leaf<i32>>().unwrap()).unwrap();
96/// let formatter = value.prepare_debug().unwrap();
97/// assert_eq!(formatter.format(&value).unwrap(), "7");
98/// ```
99#[derive(Clone)]
100pub struct ValueFormatter {
101 value_type: ValueType,
102}
103
104impl ValueFormatter {
105 /// Formats a matching live value using this previously prepared debug capability.
106 ///
107 /// # Errors
108 /// Rejects a complete shape mismatch before invoking any formatter.
109 /// - Complexity: O(n + v + s) for n type nodes, v values and s output bytes,
110 /// excluding leaf formatting costs.
111 ///
112 /// # Examples
113 /// See [`OwnedValue::prepare_debug`].
114 pub fn format(&self, value: &OwnedValue) -> anyhow::Result<String> {
115 anyhow::ensure!(
116 self.value_type.same_shape(value.value_type()),
117 "formatter value shape mismatch"
118 );
119 let mut output = String::new();
120 // SAFETY: Preparation checks every debug hook; the boundary checks full shape.
121 unsafe { debug_raw(&self.value_type, value.as_ptr(), &mut output) };
122 Ok(output)
123 }
124}
125
126impl OwnedValue {
127 /// Prepares an independent reusable formatter without consuming or formatting this value.
128 ///
129 /// # Errors
130 /// Rejects absent debug capability at any recursive node.
131 ///
132 /// # Examples
133 /// ```
134 /// use cel_runtime::{Leaf, OwnedValue, ValueType};
135 /// let value = OwnedValue::new::<Leaf<i32>>(7)
136 /// .with_value_type(ValueType::leaf::<i32>().with_debug::<Leaf<i32>>().unwrap()).unwrap();
137 /// assert_eq!(value.prepare_debug().unwrap().format(&value).unwrap(), "7");
138 /// ```
139 pub fn prepare_debug(&self) -> anyhow::Result<ValueFormatter> {
140 anyhow::ensure!(self.value_type.can_debug(), "debug capability unavailable");
141 Ok(ValueFormatter {
142 value_type: self.value_type.clone(),
143 })
144 }
145
146 /// Moves one bound array element and destroys every unselected element.
147 ///
148 /// # Safety
149 /// This owner must have the canonical array descriptor bound by the caller.
150 /// # Errors
151 /// Returns an error for an out-of-bounds index, destroying the consumed array.
152 /// - Complexity: O(n) sibling destruction for n array elements plus one raw move.
153 pub(crate) unsafe fn take_array_element(mut self, index: usize) -> anyhow::Result<Self> {
154 let ValueKind::Array(element) = self.value_type.kind() else {
155 unreachable!("validated canonical array projection")
156 };
157 let raw = unsafe { &*self.as_ptr().cast::<RawArray>() };
158 anyhow::ensure!(
159 index < raw.len,
160 "array index {index} is out of bounds for length {}",
161 raw.len
162 );
163 let allocation = Allocation::new(element.layout());
164 unsafe {
165 std::ptr::copy_nonoverlapping(
166 raw.ptr.as_ptr().cast::<u8>().add(index * element.size()),
167 allocation.pointer.as_ptr(),
168 element.size(),
169 );
170 }
171 let result = unsafe { Self::from_allocation(allocation, element.clone()) };
172 let _payload = Allocation {
173 pointer: raw.ptr.cast(),
174 layout: array_layout(element, raw.capacity),
175 };
176 /// Destroys the still-owned array elements during normal and unwinding cleanup.
177 struct Siblings<'a> {
178 base: *mut u8,
179 element: &'a ValueType,
180 remaining: usize,
181 skip: usize,
182 }
183 impl Siblings<'_> {
184 /// Destroys unselected elements in reverse index order.
185 fn destroy(&mut self) {
186 while self.remaining != 0 {
187 self.remaining -= 1;
188 if self.remaining != self.skip {
189 unsafe {
190 drop_raw(
191 self.element,
192 self.base.add(self.remaining * self.element.size()),
193 )
194 };
195 }
196 }
197 }
198 }
199 impl Drop for Siblings<'_> {
200 /// Continues remaining element destruction after a sibling panics.
201 fn drop(&mut self) {
202 self.destroy();
203 }
204 }
205 let mut siblings = Siblings {
206 base: raw.ptr.as_ptr().cast(),
207 element,
208 remaining: raw.len,
209 skip: index,
210 };
211 self.live = false;
212 // The element allocation is handled below; release the header's metadata separately.
213 drop(
214 unsafe { &mut *self.allocation.pointer.as_ptr().cast::<RawArray>() }
215 .element_type
216 .take(),
217 );
218 siblings.destroy();
219 Ok(result)
220 }
221
222 /// Splits a canonical tuple into independent source-ordered field owners.
223 ///
224 /// Nested arrays retain their payload allocations; no leaf is cloned.
225 /// # Errors
226 /// Rejects a nontuple owner without transferring any field ownership.
227 /// - Complexity: O(n + s) field allocations and raw moves for n fields and s bytes.
228 ///
229 /// # Examples
230 /// ```
231 /// use cel_runtime::{OwnedValue, Cons, Leaf, Nil, IntoCStackList};
232 /// let tuple = OwnedValue::new::<Cons<Leaf<i32>, Nil>>((7,).into_c_stack_list());
233 /// let fields = tuple.into_fields().unwrap();
234 /// assert_eq!(fields.len(), 1);
235 /// ```
236 pub fn into_fields(mut self) -> anyhow::Result<Vec<Self>> {
237 let crate::value_type::ValueKind::Tuple(fields) = self.value_type.kind() else {
238 anyhow::bail!("canonical tuple owner required");
239 };
240 let destinations: Vec<_> = fields
241 .iter()
242 .map(|field| {
243 (
244 Allocation::new(field.value_type.layout()),
245 field.offset,
246 field.value_type.clone(),
247 )
248 })
249 .collect();
250 let mut result = Vec::with_capacity(destinations.len());
251 let source = self.as_ptr();
252 // Every allocation precedes the first transfer; no callback, allocation,
253 // or fallible operation follows disarming this enclosing owner.
254 self.live = false;
255 for (allocation, offset, value_type) in destinations {
256 unsafe {
257 std::ptr::copy_nonoverlapping(
258 source.add(offset),
259 allocation.pointer.as_ptr(),
260 value_type.size(),
261 );
262 result.push(Self::from_allocation(allocation, value_type));
263 }
264 }
265 Ok(result)
266 }
267
268 /// Moves a previously validated tuple field and destroys the remaining fields.
269 ///
270 /// # Safety
271 /// This owner must be a canonical tuple and `index` must be in range.
272 /// The caller must bind the returned field's full descriptor before execution.
273 /// - Complexity: O(n) destruction calls for n fields plus one field move.
274 pub(crate) unsafe fn take_field(mut self, index: usize) -> Self {
275 let crate::value_type::ValueKind::Tuple(fields) = self.value_type.kind() else {
276 unreachable!("validated tuple projection")
277 };
278 let selected = &fields[index];
279 let allocation = Allocation::new(selected.value_type.layout());
280 unsafe {
281 std::ptr::copy_nonoverlapping(
282 self.as_ptr().add(selected.offset),
283 allocation.pointer.as_ptr(),
284 selected.value_type.size(),
285 );
286 }
287 let result = unsafe { Self::from_allocation(allocation, selected.value_type.clone()) };
288 self.live = false;
289 /// Continues sibling destruction if one sibling destructor unwinds.
290 struct Siblings<'a> {
291 pointer: *mut u8,
292 fields: &'a [crate::value_type::AssociatedType],
293 remaining: usize,
294 skip: usize,
295 }
296 impl Siblings<'_> {
297 /// Destroys unselected fields in reverse source order.
298 fn destroy(&mut self) {
299 while self.remaining != 0 {
300 self.remaining -= 1;
301 if self.remaining != self.skip {
302 let field = &self.fields[self.remaining];
303 unsafe { drop_raw(&field.value_type, self.pointer.add(field.offset)) };
304 }
305 }
306 }
307 }
308 impl Drop for Siblings<'_> {
309 /// Continues cleanup after the first destructor panic.
310 fn drop(&mut self) {
311 self.destroy();
312 }
313 }
314 let mut siblings = Siblings {
315 pointer: self.allocation.pointer.as_ptr(),
316 fields,
317 remaining: fields.len(),
318 skip: index,
319 };
320 siblings.destroy();
321 result
322 }
323 /// Adopts an allocation containing one fully initialized canonical value.
324 ///
325 /// # Safety
326 ///
327 /// The allocation must uniquely own one live value of exactly `value_type`,
328 /// including all nested allocations, with no other destruction responsibility.
329 pub(crate) unsafe fn from_allocation(allocation: Allocation, value_type: ValueType) -> Self {
330 debug_assert_eq!(allocation.layout, value_type.layout());
331 Self {
332 allocation,
333 value_type,
334 live: true,
335 }
336 }
337
338 /// Takes ownership using the sealed witness's canonical descriptor.
339 ///
340 /// Moving an array copies only its header and preserves its element allocation.
341 ///
342 /// - Complexity: O(n) descriptor construction plus one concrete value move,
343 /// for n witness nodes; no contained values are cloned.
344 ///
345 /// # Examples
346 ///
347 /// ```
348 /// use cel_runtime::{owned_value::OwnedValue, value_type::Leaf};
349 /// let _ = OwnedValue::new::<Leaf<String>>(String::from("owned"));
350 /// ```
351 pub fn new<R: ValueRepr>(value: R::Value) -> Self {
352 let value_type = R::value_type();
353 debug_assert_eq!(value_type.layout(), Layout::new::<R::Value>());
354 let allocation = Allocation::new(value_type.layout());
355 // SAFETY: The sealed witness supplies precisely R::Value's layout.
356 unsafe { allocation.pointer.as_ptr().cast::<R::Value>().write(value) };
357 Self {
358 allocation,
359 value_type,
360 live: true,
361 }
362 }
363
364 /// Borrows this whole value's frozen descriptor.
365 ///
366 /// # Examples
367 ///
368 /// ```
369 /// use cel_runtime::{owned_value::OwnedValue, value_type::{Leaf, ValueType}};
370 /// let owner = OwnedValue::new::<Leaf<i32>>(1);
371 /// assert!(owner.value_type().same_shape(&ValueType::leaf::<i32>()));
372 /// ```
373 pub fn value_type(&self) -> &ValueType {
374 &self.value_type
375 }
376
377 /// Attaches independently configured capabilities after complete shape validation.
378 ///
379 /// The live representation and allocation do not change.
380 ///
381 /// - Complexity: O(n) comparison time and O(d) call space for n type nodes
382 /// and nesting depth d.
383 ///
384 /// # Errors
385 ///
386 /// Returns an error if any identity or physical layout differs. On error the
387 /// consumed original is destroyed exactly once using its original descriptor;
388 /// none of the supplied descriptor's value hooks execute.
389 ///
390 /// # Examples
391 ///
392 /// ```
393 /// use cel_runtime::{owned_value::OwnedValue, value_type::{Leaf, ValueType}};
394 /// let owner = OwnedValue::new::<Leaf<String>>(String::from("clone me"))
395 /// .with_value_type(ValueType::cloneable_leaf::<String>()).unwrap();
396 /// assert!(owner.try_clone().is_ok());
397 /// ```
398 pub fn with_value_type(mut self, value_type: ValueType) -> anyhow::Result<Self> {
399 anyhow::ensure!(
400 self.value_type.same_shape(&value_type),
401 "value representation mismatch"
402 );
403 self.value_type = value_type;
404 Ok(self)
405 }
406
407 /// Moves into the concrete witness type after checking the entire descriptor.
408 ///
409 /// - Postcondition: Success preserves contained allocations and transfers
410 /// ownership without cloning or running value destructors.
411 /// - Complexity: O(n) witness construction and comparison for n type nodes,
412 /// plus a move of the concrete representation.
413 ///
414 /// # Errors
415 ///
416 /// Returns an error on any identity or physical layout mismatch. The consumed
417 /// original is then destroyed exactly once; no unrelated typed access occurs.
418 ///
419 /// # Examples
420 ///
421 /// ```
422 /// use cel_runtime::{owned_value::OwnedValue, value_type::Leaf};
423 /// assert_eq!(OwnedValue::new::<Leaf<i32>>(7)
424 /// .try_into_typed::<Leaf<i32>>().unwrap(), 7);
425 /// ```
426 pub fn try_into_typed<R: ValueRepr>(mut self) -> anyhow::Result<R::Value> {
427 self.value_type.validate::<R>()?;
428 let mut destination = MaybeUninit::<R::Value>::uninit();
429 // SAFETY: Complete validation established the exact destination type.
430 unsafe {
431 self.move_into(destination.as_mut_ptr().cast());
432 Ok(destination.assume_init())
433 }
434 }
435
436 /// Moves into an exact previously bound concrete representation.
437 ///
438 /// # Safety
439 /// This owner's complete descriptor must match `R`, not merely its carrier.
440 /// - Complexity: O(s) for s representation bytes.
441 ///
442 /// # Examples
443 /// Prefer [`Self::try_into_typed`] at checked host boundaries.
444 pub unsafe fn into_typed_bound<R: ValueRepr>(mut self) -> R::Value {
445 let mut destination = MaybeUninit::<R::Value>::uninit();
446 unsafe {
447 self.move_into(destination.as_mut_ptr().cast());
448 destination.assume_init()
449 }
450 }
451
452 /// Clones through the frozen plan without consuming or mutating this value.
453 ///
454 /// If a leaf clone panics, every completed cloned prefix is destroyed and
455 /// its storage released; this original remains live.
456 ///
457 /// - Complexity: O(v) traversal time, O(d) call space, and storage for the
458 /// cloned values, excluding leaf clone costs; v counts contained values.
459 ///
460 /// # Errors
461 ///
462 /// Returns an error before cloning anything if cloning is unavailable.
463 ///
464 /// # Examples
465 ///
466 /// ```
467 /// use cel_runtime::{owned_value::OwnedValue, value_type::{Leaf, ValueType}};
468 /// let original = OwnedValue::new::<Leaf<String>>(String::from("leaf"))
469 /// .with_value_type(ValueType::cloneable_leaf::<String>()).unwrap();
470 /// assert_eq!(original.try_clone().unwrap()
471 /// .try_into_typed::<Leaf<String>>().unwrap(), "leaf");
472 /// ```
473 pub fn try_clone(&self) -> anyhow::Result<Self> {
474 anyhow::ensure!(self.value_type.can_clone(), "clone capability unavailable");
475 let mut cloned = Self {
476 allocation: Allocation::new(self.value_type.layout()),
477 value_type: self.value_type.clone(),
478 live: false,
479 };
480 // SAFETY: The frozen plan is cloneable and both allocations match it.
481 unsafe {
482 clone_raw(
483 &self.value_type,
484 self.as_ptr(),
485 cloned.allocation.pointer.as_ptr(),
486 )
487 };
488 cloned.live = true;
489 Ok(cloned)
490 }
491
492 /// Compares same-shaped values through this owner's independent equality plan.
493 ///
494 /// The other owner's capability configuration need not match this one's.
495 ///
496 /// - Complexity: O(n + v) worst-case traversal time and O(d) call space,
497 /// excluding leaf equality costs, for n type nodes and v contained values.
498 ///
499 /// # Errors
500 ///
501 /// Returns an error without invoking equality if shapes differ or this
502 /// owner's equality capability is absent. Neither owner is consumed.
503 ///
504 /// # Examples
505 ///
506 /// ```
507 /// use cel_runtime::{owned_value::OwnedValue, value_type::{Leaf, ValueType}};
508 /// let a = OwnedValue::new::<Leaf<i32>>(1)
509 /// .with_value_type(ValueType::leaf::<i32>().with_equality::<Leaf<i32>>().unwrap())
510 /// .unwrap();
511 /// assert!(a.try_eq(&OwnedValue::new::<Leaf<i32>>(1)).unwrap());
512 /// ```
513 pub fn try_eq(&self, other: &Self) -> anyhow::Result<bool> {
514 anyhow::ensure!(
515 self.value_type.same_shape(&other.value_type),
516 "value representation mismatch"
517 );
518 anyhow::ensure!(
519 self.value_type.can_compare(),
520 "equality capability unavailable"
521 );
522 // SAFETY: Both live values match this prevalidated comparable plan.
523 Ok(unsafe { equal_raw(&self.value_type, self.as_ptr(), other.as_ptr()) })
524 }
525
526 /// Formats through the independent debug plan without consuming the value.
527 ///
528 /// Structural arrays use brackets; tuples use parentheses in source order.
529 ///
530 /// - Complexity: O(v + s) time, O(d) call space, and O(s) output storage,
531 /// excluding leaf formatting costs, for v values and s output bytes.
532 ///
533 /// # Errors
534 ///
535 /// Returns an error before formatting anything if debug support is absent.
536 ///
537 /// # Examples
538 ///
539 /// ```
540 /// use cel_runtime::{owned_value::OwnedValue, value_type::{Leaf, ValueType}};
541 /// let owner = OwnedValue::new::<Leaf<i32>>(7)
542 /// .with_value_type(ValueType::leaf::<i32>().with_debug::<Leaf<i32>>().unwrap())
543 /// .unwrap();
544 /// assert_eq!(owner.try_debug().unwrap(), "7");
545 /// ```
546 pub fn try_debug(&self) -> anyhow::Result<String> {
547 anyhow::ensure!(self.value_type.can_debug(), "debug capability unavailable");
548 let mut output = String::new();
549 // SAFETY: This live value matches its prevalidated debug plan.
550 unsafe { debug_raw(&self.value_type, self.as_ptr(), &mut output) };
551 Ok(output)
552 }
553
554 /// Borrows the raw representation for trusted, already validated execution.
555 ///
556 /// The pointer remains live only while this owner remains borrowed.
557 ///
558 /// # Examples
559 /// ```
560 /// let owner = cel_runtime::OwnedValue::new::<cel_runtime::Leaf<i32>>(1);
561 /// assert!(!owner.as_ptr().is_null());
562 /// ```
563 pub fn as_ptr(&self) -> *const u8 {
564 debug_assert!(self.live);
565 self.allocation.pointer.as_ptr()
566 }
567
568 /// Compares values whose complete identity has already been bound by a host.
569 ///
570 /// # Safety
571 /// Both owners must have exactly the same complete shape, and this owner's
572 /// descriptor must support equality.
573 /// - Complexity: O(v) for v contained values, excluding leaf comparison costs.
574 ///
575 /// # Examples
576 /// Use [`Self::try_eq`] at checked host boundaries.
577 pub unsafe fn eq_bound(&self, other: &Self) -> bool {
578 unsafe { equal_raw(&self.value_type, self.as_ptr(), other.as_ptr()) }
579 }
580
581 /// Transfers the representation without any runtime identity checks.
582 ///
583 /// - Postcondition: This owner no longer destroys the transferred value.
584 /// - Complexity: O(s) bytes copied for representation size s.
585 ///
586 /// # Safety
587 ///
588 /// The caller must have prevalidated the full identity and layout. The
589 /// destination must be aligned, disjoint uninitialized storage for exactly
590 /// this representation, and must assume unique destruction responsibility.
591 pub(crate) unsafe fn move_into(&mut self, destination: *mut u8) {
592 debug_assert!(self.live);
593 // SAFETY: The caller guarantees disjoint storage of the validated size.
594 // Byte copying preserves potentially uninitialized padding without reading it.
595 unsafe {
596 ptr::copy_nonoverlapping(self.as_ptr(), destination, self.value_type.layout().size());
597 }
598 self.live = false;
599 }
600}
601
602impl Drop for OwnedValue {
603 /// Destroys the live value before its allocation is automatically released.
604 fn drop(&mut self) {
605 if self.live {
606 self.live = false;
607 // SAFETY: This owner uniquely owns one initialized value of this plan.
608 unsafe { drop_raw(&self.value_type, self.allocation.pointer.as_ptr()) };
609 }
610 }
611}
612
613/// Describes initialized children without per-element descriptors or allocations.
614pub(crate) enum Children<'a> {
615 /// Source-ordered tuple fields at canonical offsets.
616 Fields(&'a [AssociatedType]),
617 /// Homogeneous elements at their concrete stride.
618 Elements(&'a ValueType),
619}
620
621impl Children<'_> {
622 /// Locates one initialized child relative to the aggregate base.
623 fn child(&self, index: usize) -> (&ValueType, usize) {
624 match self {
625 Self::Fields(fields) => (&fields[index].value_type, fields[index].offset),
626 Self::Elements(element) => (element, index * element.layout().size()),
627 }
628 }
629}
630
631/// Destroys a live child prefix backwards, including remaining children on unwind.
632pub(crate) struct Prefix<'a> {
633 pub(crate) base: *mut u8,
634 pub(crate) children: Children<'a>,
635 pub(crate) initialized: usize,
636}
637
638impl Prefix<'_> {
639 /// Destroys remaining initialized children in reverse logical order.
640 ///
641 /// Decrements the live prefix before each destructor so this guard's own
642 /// destructor resumes at the next child if the first destructor unwinds.
643 ///
644 /// - Complexity: O(n) child destructions and O(1) local space.
645 ///
646 /// # Safety
647 ///
648 /// The prefix must uniquely own exactly `initialized` live children matching
649 /// `children`, at their validated offsets from `base`.
650 pub(crate) unsafe fn destroy(&mut self) {
651 while self.initialized != 0 {
652 self.initialized -= 1;
653 let (value_type, offset) = self.children.child(self.initialized);
654 unsafe { drop_raw(value_type, self.base.add(offset)) };
655 }
656 }
657}
658
659impl Drop for Prefix<'_> {
660 /// Destroys any initialized children not yet transferred or destroyed.
661 fn drop(&mut self) {
662 // SAFETY: Private construction and prefix updates maintain live ownership.
663 unsafe { self.destroy() };
664 }
665}
666
667/// Returns the exact global-allocation layout for a concrete array capacity.
668///
669/// - Precondition: Capacity comes from a valid array header of this element type.
670fn array_layout(element: &ValueType, capacity: usize) -> Layout {
671 Layout::from_size_align(
672 element
673 .layout()
674 .size()
675 .checked_mul(capacity)
676 .expect("valid array capacity"),
677 element.layout().align(),
678 )
679 .expect("valid array allocation layout")
680}
681
682/// Destroys a prevalidated live representation and all its owned allocations.
683///
684/// - Complexity: O(v) traversal time and O(d) call space for v values and depth d.
685///
686/// # Safety
687///
688/// `pointer` must uniquely own one aligned live value matching `value_type`.
689pub(crate) unsafe fn drop_raw(value_type: &ValueType, pointer: *mut u8) {
690 if let Some(dropper) = value_type.leaf_drop() {
691 unsafe { dropper(pointer) };
692 return;
693 }
694 match value_type.kind() {
695 ValueKind::Tuple(fields) => {
696 let mut prefix = Prefix {
697 base: pointer,
698 children: Children::Fields(fields),
699 initialized: fields.len(),
700 };
701 unsafe { prefix.destroy() };
702 }
703 ValueKind::Array(_) => unsafe { pointer.cast::<RawArray>().drop_in_place() },
704 // No public constructor supplies callable storage before its carrier exists.
705 ValueKind::Leaf(_) | ValueKind::Callable { .. } => unreachable!("missing ownership plan"),
706 }
707}
708
709/// Clones through a frozen, prevalidated plan with panic-safe prefix ownership.
710///
711/// - Complexity: O(v) traversal time, O(d) call space, and cloned value storage.
712///
713/// # Safety
714///
715/// The plan must support cloning. Source must be live and aligned; destination
716/// must be disjoint, aligned uninitialized storage of the same complete shape.
717/// A panic leaves no initialized value in the destination.
718pub(crate) unsafe fn clone_raw(value_type: &ValueType, source: *const u8, destination: *mut u8) {
719 debug_assert!(value_type.can_clone());
720 if let Some(cloner) = value_type.clone_hook() {
721 unsafe { cloner(source, destination) };
722 return;
723 }
724 match value_type.kind() {
725 ValueKind::Tuple(fields) => {
726 let mut prefix = Prefix {
727 base: destination,
728 children: Children::Fields(fields),
729 initialized: 0,
730 };
731 for field in fields {
732 unsafe {
733 clone_raw(
734 &field.value_type,
735 source.add(field.offset),
736 destination.add(field.offset),
737 );
738 }
739 prefix.initialized += 1;
740 }
741 prefix.initialized = 0;
742 }
743 ValueKind::Array(element) => {
744 let source = unsafe { &*source.cast::<RawArray>() };
745 let capacity = if element.layout().size() == 0 {
746 usize::MAX
747 } else {
748 source.len
749 };
750 let allocation = Allocation::new(array_layout(element, capacity));
751 let mut prefix = Prefix {
752 base: allocation.pointer.as_ptr(),
753 children: Children::Elements(element),
754 initialized: 0,
755 };
756 for index in 0..source.len {
757 let offset = index * element.layout().size();
758 unsafe {
759 clone_raw(
760 element,
761 source.ptr.as_ptr().cast::<u8>().add(offset),
762 allocation.pointer.as_ptr().add(offset),
763 );
764 }
765 prefix.initialized += 1;
766 }
767 unsafe {
768 destination.cast::<RawArray>().write(RawArray::from_erased(
769 allocation.pointer.cast(),
770 source.len,
771 capacity,
772 element.clone(),
773 ));
774 }
775 prefix.initialized = 0;
776 std::mem::forget(allocation);
777 }
778 ValueKind::Leaf(_) | ValueKind::Callable { .. } => unreachable!("missing clone plan"),
779 }
780}
781
782/// Compares live values using a prevalidated complete equality plan.
783///
784/// - Complexity: O(v) traversal time and O(d) call space, excluding leaf costs.
785///
786/// # Safety
787///
788/// Both live values must match the complete comparable descriptor.
789unsafe fn equal_raw(value_type: &ValueType, left: *const u8, right: *const u8) -> bool {
790 if let Some(equal) = value_type.equality_hook() {
791 return unsafe { equal(left, right) };
792 }
793 match value_type.kind() {
794 ValueKind::Tuple(fields) => fields.iter().all(|field| unsafe {
795 equal_raw(
796 &field.value_type,
797 left.add(field.offset),
798 right.add(field.offset),
799 )
800 }),
801 ValueKind::Array(element) => {
802 let left = unsafe { &*left.cast::<RawArray>() };
803 let right = unsafe { &*right.cast::<RawArray>() };
804 left.len == right.len
805 && (0..left.len).all(|index| unsafe {
806 let offset = index * element.layout().size();
807 equal_raw(
808 element,
809 left.ptr.as_ptr().cast::<u8>().add(offset),
810 right.ptr.as_ptr().cast::<u8>().add(offset),
811 )
812 })
813 }
814 ValueKind::Leaf(_) | ValueKind::Callable { .. } => unreachable!("missing equality plan"),
815 }
816}
817
818/// Formats live values in source order using a prevalidated debug plan.
819///
820/// - Complexity: O(v + s) time and O(d + s) space, excluding leaf costs.
821///
822/// # Safety
823///
824/// The live value must match the complete debug-capable descriptor.
825unsafe fn debug_raw(value_type: &ValueType, pointer: *const u8, output: &mut String) {
826 if let Some(debug) = value_type.debug_hook() {
827 unsafe { debug(pointer, output) };
828 return;
829 }
830 match value_type.kind() {
831 ValueKind::Tuple(fields) => {
832 output.push('(');
833 for (index, field) in fields.iter().enumerate() {
834 if index != 0 {
835 output.push_str(", ");
836 }
837 unsafe { debug_raw(&field.value_type, pointer.add(field.offset), output) };
838 }
839 if fields.len() == 1 {
840 output.push(',');
841 }
842 output.push(')');
843 }
844 ValueKind::Array(element) => {
845 output.push('[');
846 let raw = unsafe { &*pointer.cast::<RawArray>() };
847 for index in 0..raw.len {
848 if index != 0 {
849 output.push_str(", ");
850 }
851 unsafe {
852 debug_raw(
853 element,
854 raw.ptr
855 .as_ptr()
856 .cast::<u8>()
857 .add(index * element.layout().size()),
858 output,
859 )
860 };
861 }
862 output.push(']');
863 }
864 ValueKind::Leaf(_) | ValueKind::Callable { .. } => unreachable!("missing debug plan"),
865 }
866}