bones_schema/
ptr.rs

1//! Schema-aware smart pointers.
2
3use std::{
4    alloc::handle_alloc_error,
5    any::{type_name, TypeId},
6    ffi::c_void,
7    hash::Hash,
8    iter::{Filter, Map},
9    marker::PhantomData,
10    mem::MaybeUninit,
11    ptr::NonNull,
12    str::Split,
13    sync::OnceLock,
14};
15
16use bones_utils::prelude::*;
17use parking_lot::RwLock;
18use ustr::Ustr;
19
20use crate::{
21    prelude::*,
22    raw_fns::{RawClone, RawDefault, RawDrop},
23};
24
25/// An untyped reference that knows the [`Schema`] of the pointee and that can be cast to a matching
26/// type.
27#[derive(Clone, Copy)]
28pub struct SchemaRef<'pointer> {
29    ptr: NonNull<c_void>,
30    schema: &'static Schema,
31    _phantom: PhantomData<&'pointer ()>,
32}
33
34impl<'pointer> SchemaRef<'pointer> {
35    /// Unsafely cast this pointer to a specifc Rust type.
36    /// # Safety
37    /// All of the safety requirements of [`NonNull::as_ref()`] must be met.
38    pub unsafe fn cast_unchecked<T>(&self) -> &T {
39        self.ptr.cast::<T>().as_ref()
40    }
41
42    /// Unsafely cast this pointer to a specifc Rust type.
43    /// # Safety
44    /// All of the safety requirements of [`NonNull::as_ref()`] must be met.
45    pub unsafe fn cast_into_unchecked<T>(self) -> &'pointer T {
46        self.ptr.cast::<T>().as_ref()
47    }
48
49    /// Cast this pointer to a reference to a type with a matching [`Schema`].
50    ///
51    /// # Panics
52    ///
53    /// Panics if the schema of the pointer does not match that of the type you are casting to.
54    #[track_caller]
55    pub fn cast<T: HasSchema>(&self) -> &'pointer T {
56        self.try_cast().expect(SchemaMismatchError::MSG)
57    }
58
59    /// Cast this pointer to a reference to a type with a matching [`Schema`].
60    ///
61    /// # Errors
62    ///
63    /// Errors if the schema of the pointer does not match that of the type you are casting to.
64    pub fn try_cast<T: HasSchema>(&self) -> Result<&'pointer T, SchemaMismatchError> {
65        if self.schema.represents(T::schema()) {
66            // SOUND: the schemas have the same memory representation.
67            Ok(unsafe { self.cast_into_unchecked() })
68        } else {
69            Err(SchemaMismatchError)
70        }
71    }
72
73    /// Create a new [`SchemaRef`] from a reference to a type that implements [`HasSchema`].
74    pub fn new<T: HasSchema>(v: &'pointer T) -> SchemaRef<'pointer> {
75        let schema = T::schema();
76        SchemaRef {
77            // SOUND: The &T passed in cannot be null.
78            ptr: unsafe { NonNull::new_unchecked(v as *const T as *mut c_void) },
79            schema,
80            _phantom: PhantomData,
81        }
82    }
83
84    /// Create a new [`SchemaRef`] from a raw pointer and it's schema.
85    ///
86    /// # Safety
87    /// - The pointee of `ptr` must be accurately described by the given `schema`.
88    /// - `inner` must have correct provenance to allow read of the pointee type.
89    /// - The pointer must be valid for the full lifetime of this [`SchemaRef`].
90    #[track_caller]
91    pub unsafe fn from_ptr_schema(ptr: *const c_void, schema: &'static Schema) -> Self {
92        Self {
93            ptr: NonNull::new_unchecked(ptr as *mut c_void),
94            schema,
95            _phantom: PhantomData,
96        }
97    }
98
99    /// Get the pointer.
100    pub fn as_ptr(&self) -> *const c_void {
101        self.ptr.as_ptr()
102    }
103
104    /// Get the [`Schema`] for the pointer.
105    pub fn schema(&self) -> &'static Schema {
106        self.schema
107    }
108
109    /// Get the hash of this schema box, if supported.
110    pub fn hash(&self) -> Option<u64> {
111        self.schema
112            .hash_fn
113            .as_ref()
114            .map(|hash_fn| unsafe { (hash_fn.get())(self.ptr.as_ptr()) })
115    }
116
117    /// Borrow the schema ref as a [`SchemaMap`] if it is one.
118    pub fn as_map(&self) -> Option<&'pointer SchemaMap> {
119        matches!(self.schema.kind, SchemaKind::Map { .. })
120            // SOUND: Schema asserts this is a schema map
121            .then(|| unsafe { self.cast_into_unchecked::<SchemaMap>() })
122    }
123
124    /// Borrow the schema ref as a [`SchemaVec`] if it is one.
125    pub fn as_vec(&self) -> Option<&'pointer SchemaVec> {
126        matches!(self.schema.kind, SchemaKind::Vec(_))
127            // SOUND: Schema asserts this is a schema map
128            .then(|| unsafe { self.cast_into_unchecked::<SchemaVec>() })
129    }
130
131    /// Borrow the schema ref as a [`SchemaBox`] if it is one.
132    pub fn as_box(&self) -> Option<SchemaRef<'pointer>> {
133        matches!(self.schema.kind, SchemaKind::Vec(_))
134            // SOUND: Schema asserts this is a schema box
135            .then(|| unsafe { self.cast_into_unchecked::<SchemaBox>().as_ref() })
136    }
137
138    /// Debug format the value stored in the schema box.
139    ///
140    /// This is used in the display and debug implementations.
141    pub fn debug_format_value(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
142        f.write_fmt(format_args!("{:?}", self.access_borrowed()))
143    }
144
145    /// Get a helper to access the inner data.
146    pub fn access(self) -> SchemaRefAccess<'pointer> {
147        SchemaRefAccess::new(self)
148    }
149
150    /// Get a helper to access the inner without consuming this reference.
151    fn access_borrowed(&self) -> SchemaRefAccess<'_> {
152        SchemaRefAccess::new_borrowed(self)
153    }
154
155    /// Get the reference to a field.
156    pub fn field<'a, I: Into<FieldIdx<'a>>>(self, field_idx: I) -> Option<SchemaRef<'pointer>> {
157        Some(self.access().field(field_idx)?.into_schema_ref())
158    }
159
160    /// Get the field pointed to by the given path.
161    pub fn field_path<'a, I: IntoIterator<Item = FieldIdx<'a>>>(self, path: I) -> Option<Self> {
162        let mut current_field = self;
163        for field_idx in path {
164            current_field = current_field.field(field_idx)?;
165        }
166        Some(current_field)
167    }
168
169    /// Clone this schema ref into a new box.
170    pub fn clone_into_box(&self) -> SchemaBox {
171        let Some(clone_fn) = &self.schema.clone_fn else {
172            panic!(
173                "The schema for type `{}` does not allow cloning it.",
174                self.schema.full_name
175            );
176        };
177        unsafe {
178            let b = SchemaBox::uninitialized(self.schema);
179            (clone_fn.get())(self.ptr.as_ptr(), b.ptr.as_ptr());
180            b
181        }
182    }
183}
184
185struct SchemaRefValueDebug<'a>(SchemaRef<'a>);
186impl std::fmt::Debug for SchemaRefValueDebug<'_> {
187    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
188        self.0.debug_format_value(f)
189    }
190}
191
192impl std::fmt::Debug for SchemaRef<'_> {
193    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
194        f.debug_tuple("SchemaRef<'_>")
195            .field(&SchemaRefValueDebug(*self))
196            .finish()
197    }
198}
199impl std::fmt::Display for SchemaRef<'_> {
200    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
201        <SchemaRefValueDebug as std::fmt::Debug>::fmt(&SchemaRefValueDebug(*self), f)
202    }
203}
204
205/// Helper for accessing the inner data of a schema ref at runtime.
206#[derive(Clone, Copy)]
207pub enum SchemaRefAccess<'a> {
208    /// Access a struct.
209    Struct(StructRefAccess<'a>),
210    /// Access a vec.
211    Vec(SchemaVecAccess<'a>),
212    /// Access an enum.
213    Enum(EnumRefAccess<'a>),
214    /// Access a map.
215    Map(SchemaMapAccess<'a>),
216    /// Access a struct.
217    Primitive(PrimitiveRef<'a>),
218}
219
220impl std::fmt::Debug for SchemaRefAccess<'_> {
221    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
222        match self {
223            SchemaRefAccess::Struct(s) => {
224                let is_tuple = s.fields().any(|x| x.name.is_none());
225                if is_tuple {
226                    let mut builder = f.debug_tuple(&s.schema().name);
227                    for field in s.fields() {
228                        builder.field(&SchemaRefValueDebug(field.value));
229                    }
230                    builder.finish()
231                } else {
232                    let mut builder = f.debug_struct(&s.schema().name);
233                    for field in s.fields() {
234                        builder.field(field.name.unwrap(), &SchemaRefValueDebug(field.value));
235                    }
236                    builder.finish()
237                }
238            }
239            SchemaRefAccess::Vec(v) => {
240                let mut builder = f.debug_list();
241                for item in v.iter() {
242                    builder.entry(&SchemaRefValueDebug(item));
243                }
244                builder.finish()
245            }
246            SchemaRefAccess::Enum(e) => {
247                f.write_fmt(format_args!("{:?}", SchemaRefValueDebug(e.value().0)))
248            }
249            SchemaRefAccess::Map(m) => {
250                let mut builder = f.debug_map();
251                for (key, value) in m.iter() {
252                    builder.key(&SchemaRefValueDebug(key));
253                    builder.value(&SchemaRefValueDebug(value));
254                }
255                builder.finish()
256            }
257            SchemaRefAccess::Primitive(p) => match p {
258                PrimitiveRef::Bool(b) => f.write_fmt(format_args!("{b}")),
259                PrimitiveRef::U8(n) => f.write_fmt(format_args!("{n}")),
260                PrimitiveRef::U16(n) => f.write_fmt(format_args!("{n}")),
261                PrimitiveRef::U32(n) => f.write_fmt(format_args!("{n}")),
262                PrimitiveRef::U64(n) => f.write_fmt(format_args!("{n}")),
263                PrimitiveRef::U128(n) => f.write_fmt(format_args!("{n}")),
264                PrimitiveRef::I8(n) => f.write_fmt(format_args!("{n}")),
265                PrimitiveRef::I16(n) => f.write_fmt(format_args!("{n}")),
266                PrimitiveRef::I32(n) => f.write_fmt(format_args!("{n}")),
267                PrimitiveRef::I64(n) => f.write_fmt(format_args!("{n}")),
268                PrimitiveRef::I128(n) => f.write_fmt(format_args!("{n}")),
269                PrimitiveRef::F32(n) => f.write_fmt(format_args!("{n}")),
270                PrimitiveRef::F64(n) => f.write_fmt(format_args!("{n}")),
271                PrimitiveRef::String(s) => f.write_fmt(format_args!("{s:?}")),
272                PrimitiveRef::Opaque {
273                    size,
274                    align,
275                    schema_ref,
276                } => f
277                    .debug_tuple(&schema_ref.schema.name)
278                    .field(&Primitive::Opaque {
279                        size: *size,
280                        align: *align,
281                    })
282                    .finish(),
283            },
284        }
285    }
286}
287
288impl<'ptr> SchemaRefAccess<'ptr> {
289    /// Create a new [`SchemaRefAccess`] for the given [`SchemaRef`].
290    ///
291    /// This will create a new independent [`SchemaRefAccess`] that may be used even after
292    /// the original [`SchemaRef`] is dropped ( but not beyond the safe lifetime of the
293    /// original schema ref ).
294    pub fn new(value: SchemaRef) -> SchemaRefAccess {
295        match &value.schema.kind {
296            SchemaKind::Struct(_) => SchemaRefAccess::Struct(StructRefAccess(value)),
297            SchemaKind::Vec(_) => SchemaRefAccess::Vec(SchemaVecAccess {
298                vec: value.as_vec().unwrap(),
299                orig_ref: value,
300            }),
301            SchemaKind::Enum(_) => SchemaRefAccess::Enum(EnumRefAccess(value)),
302            SchemaKind::Map { .. } => SchemaRefAccess::Map(SchemaMapAccess {
303                map: value.as_map().unwrap(),
304                orig_ref: value,
305            }),
306            SchemaKind::Box(_) => value.as_box().unwrap().access(),
307            SchemaKind::Primitive(_) => SchemaRefAccess::Primitive(value.into()),
308        }
309    }
310
311    /// Create a new [`SchemaRefAccess`] for the given [`SchemaRef`] that borrows the original
312    /// [`SchemaRef`].
313    ///
314    /// This is subtly different from [`SchemaRefAccess::new()`] because it requires that it hold
315    /// a borrow to the original schema ref it was created from. This is specifically useful becuse
316    /// it lets you create a [`SchemaRefAccess`] from a refeence to a schema ref, which is required
317    /// when accessing a schema ref that is behind an atomic resource borrow, for example.
318    pub fn new_borrowed<'borrow>(value: &'borrow SchemaRef<'_>) -> SchemaRefAccess<'borrow> {
319        match &value.schema.kind {
320            SchemaKind::Struct(_) => SchemaRefAccess::Struct(StructRefAccess(*value)),
321            SchemaKind::Vec(_) => SchemaRefAccess::Vec(SchemaVecAccess {
322                vec: value.as_vec().unwrap(),
323                orig_ref: *value,
324            }),
325            SchemaKind::Enum(_) => SchemaRefAccess::Enum(EnumRefAccess(*value)),
326            SchemaKind::Map { .. } => SchemaRefAccess::Map(SchemaMapAccess {
327                map: value.as_map().unwrap(),
328                orig_ref: *value,
329            }),
330            SchemaKind::Box(_) => value.as_box().unwrap().access(),
331            SchemaKind::Primitive(_) => SchemaRefAccess::Primitive((*value).into()),
332        }
333    }
334
335    /// Get field with the given index.
336    pub fn field<'a, I: Into<FieldIdx<'a>>>(self, field_idx: I) -> Option<Self> {
337        let field_idx = field_idx.into();
338        match self {
339            SchemaRefAccess::Struct(s) => s.field(field_idx),
340            SchemaRefAccess::Vec(_)
341            | SchemaRefAccess::Enum(_)
342            | SchemaRefAccess::Map(_)
343            | SchemaRefAccess::Primitive(_) => None,
344        }
345    }
346
347    /// Get the field pointed to by the given path.
348    pub fn field_path<'a, I: IntoIterator<Item = FieldIdx<'a>>>(self, path: I) -> Option<Self> {
349        let mut current_field = self;
350        for field_idx in path {
351            current_field = current_field.field(field_idx)?;
352        }
353        Some(current_field)
354    }
355
356    /// Borrow this [`SchemaRefMutAccess`] as a [`SchemaRefAccess`].
357    pub fn into_schema_ref(self) -> SchemaRef<'ptr> {
358        match self {
359            SchemaRefAccess::Struct(s) => s.0,
360            SchemaRefAccess::Vec(v) => v.into_schema_ref(),
361            SchemaRefAccess::Enum(e) => e.0,
362            SchemaRefAccess::Map(m) => m.into_schema_ref(),
363            SchemaRefAccess::Primitive(p) => p.into_schema_ref(),
364        }
365    }
366}
367
368/// Access helper for a [`SchemaVec`].
369#[derive(Deref, DerefMut, Clone, Copy)]
370pub struct SchemaVecAccess<'a> {
371    /// The schema vec borrow.
372    #[deref]
373    vec: &'a SchemaVec,
374    orig_ref: SchemaRef<'a>,
375}
376
377impl<'a> SchemaVecAccess<'a> {
378    /// Convert back to a [`SchemaRefMut`]
379    pub fn into_schema_ref(self) -> SchemaRef<'a> {
380        self.orig_ref
381    }
382}
383
384/// Access helper for a [`SchemaMap`].
385#[derive(Deref, DerefMut, Clone, Copy)]
386pub struct SchemaMapAccess<'a> {
387    /// The schema map borrow.
388    #[deref]
389    map: &'a SchemaMap,
390    orig_ref: SchemaRef<'a>,
391}
392
393impl<'a> SchemaMapAccess<'a> {
394    /// Convert back to a [`SchemaRefMut`]
395    pub fn into_schema_ref(self) -> SchemaRef<'a> {
396        self.orig_ref
397    }
398}
399
400/// Helper for accessing the inner data of a schema ref at runtime.
401#[derive(Clone, Copy)]
402pub struct StructRefAccess<'a>(SchemaRef<'a>);
403
404impl<'a> StructRefAccess<'a> {
405    /// Get the struct's schema.
406    pub fn schema(&self) -> &'static Schema {
407        self.0.schema
408    }
409
410    /// Get the [`StructSchemaInfo`] for this struct.
411    pub fn info(&self) -> &'static StructSchemaInfo {
412        self.0.schema.kind.as_struct().unwrap()
413    }
414
415    /// Interate over the fields on the struct.
416    pub fn fields(&self) -> StructRefFieldIter<'_> {
417        StructRefFieldIter {
418            ptr: self.0,
419            field_idx: 0,
420        }
421    }
422
423    /// Access a field, if it exists.
424    pub fn field<'i, I: Into<FieldIdx<'i>>>(self, field_idx: I) -> Option<SchemaRefAccess<'a>> {
425        let field_idx = field_idx.into();
426        let field_idx = match field_idx {
427            FieldIdx::Name(name) => self
428                .info()
429                .fields
430                .iter()
431                .position(|x| x.name.as_ref().map(|x| x.as_ref()) == Some(name))?,
432            FieldIdx::Idx(idx) => idx,
433        };
434        let field_schema = self
435            .0
436            .schema
437            .kind
438            .as_struct()
439            .unwrap()
440            .fields
441            .get(field_idx)
442            .unwrap()
443            .schema;
444        let (_, field_offset) = self.0.schema.field_offsets().get(field_idx).unwrap();
445
446        Some(unsafe {
447            SchemaRef {
448                ptr: NonNull::new_unchecked(self.0.as_ptr().add(*field_offset) as *mut c_void),
449                schema: field_schema,
450                _phantom: PhantomData,
451            }
452            .access()
453        })
454    }
455
456    /// Convert to a [`SchemaRef`].
457    pub fn as_schema_ref(&self) -> SchemaRef<'a> {
458        self.0
459    }
460}
461
462/// Iterator for [`StructRefAccess::fields()`].
463pub struct StructRefFieldIter<'a> {
464    ptr: SchemaRef<'a>,
465    field_idx: usize,
466}
467
468/// A field returned by [`StructRefFieldIter`].
469pub struct StructRefFieldIterField<'a> {
470    /// The name of the field, if set.
471    pub name: Option<&'static str>,
472    /// The field's value.
473    pub value: SchemaRef<'a>,
474}
475
476impl<'a> Iterator for StructRefFieldIter<'a> {
477    type Item = StructRefFieldIterField<'a>;
478
479    fn next(&mut self) -> Option<Self::Item> {
480        let (name, _) = self.ptr.schema.field_offsets().get(self.field_idx)?;
481        let ptr = self
482            .ptr
483            .access()
484            .field(self.field_idx)
485            .unwrap()
486            .into_schema_ref();
487        self.field_idx += 1;
488        Some(StructRefFieldIterField {
489            name: name.as_ref().map(|x| x.as_str()),
490            value: ptr,
491        })
492    }
493}
494
495/// Helper for accessing the inner data of a schema ref at runtime.
496#[derive(Clone, Copy)]
497pub struct EnumRefAccess<'a>(pub SchemaRef<'a>);
498
499impl<'a> EnumRefAccess<'a> {
500    /// Get the enum's schema.
501    pub fn schema(&self) -> &'static Schema {
502        self.0.schema
503    }
504
505    /// Get the enum schema info.
506    pub fn info(&self) -> &'static EnumSchemaInfo {
507        let SchemaKind::Enum(info) = &self.0.schema.kind else {
508            panic!("Not an enum");
509        };
510        info
511    }
512
513    /// Get the [`VariantInfo`] for the current variant.
514    pub fn variant_info(&self) -> &'static VariantInfo {
515        &self.info().variants[self.variant_idx() as usize]
516    }
517
518    /// Get the [`StructSchemaInfo`] for the current variant.
519    pub fn variant_struct_info(&self) -> &'static StructSchemaInfo {
520        self.variant_info().schema.kind.as_struct().unwrap()
521    }
522
523    /// Get the currently-selected variant index.
524    pub fn variant_idx(&self) -> u32 {
525        let info = self.info();
526        match info.tag_type {
527            EnumTagType::U8 => unsafe { self.0.as_ptr().cast::<u8>().read() as u32 },
528            EnumTagType::U16 => unsafe { self.0.as_ptr().cast::<u16>().read() as u32 },
529            EnumTagType::U32 => unsafe { self.0.as_ptr().cast::<u32>().read() },
530        }
531    }
532
533    /// Get the name of the currently selected variant.
534    pub fn variant_name(&self) -> &'static str {
535        let info = self.info();
536        let idx = self.variant_idx();
537        info.variants[idx as usize].name.as_ref()
538    }
539
540    /// Get a reference to the enum's currently selected value.
541    pub fn value(&self) -> StructRefAccess<'a> {
542        let info = self.info();
543        let variant_idx = self.variant_idx();
544        let variant_info = &info.variants[variant_idx as usize];
545        let schema = variant_info.schema;
546        let value_offset = self.0.schema.field_offsets()[0].1;
547        StructRefAccess(SchemaRef {
548            ptr: unsafe { NonNull::new_unchecked(self.0.ptr.as_ptr().add(value_offset)) },
549            schema,
550            _phantom: PhantomData,
551        })
552    }
553}
554
555/// Helper for accessing the inner data of a schema ref at runtime.
556#[derive(Clone, Copy, Debug)]
557pub enum PrimitiveRef<'a> {
558    /// A [`bool`]
559    Bool(&'a bool),
560    /// A [`u8`]
561    U8(&'a u8),
562    /// A [`u16`]
563    U16(&'a u16),
564    /// A [`u32`]
565    U32(&'a u32),
566    /// A [`u64`]
567    U64(&'a u64),
568    /// A [`u128`]
569    U128(&'a u128),
570    /// An [`i8`]
571    I8(&'a i8),
572    /// An [`i16`]
573    I16(&'a i16),
574    /// An [`i32`]
575    I32(&'a i32),
576    /// An [`i64`]
577    I64(&'a i64),
578    /// An [`i128`]
579    I128(&'a i128),
580    /// An [`f32`]
581    F32(&'a f32),
582    /// An [`f64`]
583    F64(&'a f64),
584    /// A [`String`]
585    String(&'a String),
586    /// An opaque type
587    Opaque {
588        /// The size of the opaque type.
589        size: usize,
590        /// The align of the opaque type.
591        align: usize,
592        /// The schema ref.
593        schema_ref: SchemaRef<'a>,
594    },
595}
596
597impl<'ptr> PrimitiveRef<'ptr> {
598    fn into_schema_ref(self) -> SchemaRef<'ptr> {
599        match self {
600            PrimitiveRef::Bool(b) => SchemaRef::new(b),
601            PrimitiveRef::U8(n) => SchemaRef::new(n),
602            PrimitiveRef::U16(n) => SchemaRef::new(n),
603            PrimitiveRef::U32(n) => SchemaRef::new(n),
604            PrimitiveRef::U64(n) => SchemaRef::new(n),
605            PrimitiveRef::U128(n) => SchemaRef::new(n),
606            PrimitiveRef::I8(n) => SchemaRef::new(n),
607            PrimitiveRef::I16(n) => SchemaRef::new(n),
608            PrimitiveRef::I32(n) => SchemaRef::new(n),
609            PrimitiveRef::I64(n) => SchemaRef::new(n),
610            PrimitiveRef::I128(n) => SchemaRef::new(n),
611            PrimitiveRef::F32(n) => SchemaRef::new(n),
612            PrimitiveRef::F64(n) => SchemaRef::new(n),
613            PrimitiveRef::String(s) => SchemaRef::new(s),
614            PrimitiveRef::Opaque { schema_ref, .. } => schema_ref,
615        }
616    }
617}
618
619impl<'a> From<SchemaRef<'a>> for PrimitiveRef<'a> {
620    fn from(value: SchemaRef<'a>) -> Self {
621        match &value.schema.kind {
622            SchemaKind::Primitive(p) => match p {
623                Primitive::Bool => PrimitiveRef::Bool(value.cast()),
624                Primitive::U8 => PrimitiveRef::U8(value.cast()),
625                Primitive::U16 => PrimitiveRef::U16(value.cast()),
626                Primitive::U32 => PrimitiveRef::U32(value.cast()),
627                Primitive::U64 => PrimitiveRef::U64(value.cast()),
628                Primitive::U128 => PrimitiveRef::U128(value.cast()),
629                Primitive::I8 => PrimitiveRef::I8(value.cast()),
630                Primitive::I16 => PrimitiveRef::I16(value.cast()),
631                Primitive::I32 => PrimitiveRef::I32(value.cast()),
632                Primitive::I64 => PrimitiveRef::I64(value.cast()),
633                Primitive::I128 => PrimitiveRef::I128(value.cast()),
634                Primitive::F32 => PrimitiveRef::F32(value.cast()),
635                Primitive::F64 => PrimitiveRef::F64(value.cast()),
636                Primitive::String => PrimitiveRef::String(value.cast()),
637                Primitive::Opaque { size, align } => PrimitiveRef::Opaque {
638                    size: *size,
639                    align: *align,
640                    schema_ref: value,
641                },
642            },
643            _ => panic!("Schema mismatch"),
644        }
645    }
646}
647
648/// An untyped mutable reference that knows the [`Schema`] of the pointee and that can be cast to a matching
649/// type.
650pub struct SchemaRefMut<'pointer> {
651    ptr: NonNull<c_void>,
652    schema: &'static Schema,
653    _phantom: PhantomData<&'pointer mut ()>,
654}
655
656impl<'pointer> std::fmt::Debug for SchemaRefMut<'pointer> {
657    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
658        f.debug_struct("SchemaRefMut")
659            // .field("ptr", &self.ptr)
660            .field("schema", &self.schema)
661            // .field("parent_lifetime", &self.parent_lifetime)
662            .finish()
663    }
664}
665
666impl<'pointer> SchemaRefMut<'pointer> {
667    /// Cast this pointer to a mutable reference.
668    /// # Safety
669    /// You must uphold all safety requirements of [`NonNull::as_mut()`].
670    pub unsafe fn cast_mut_unchecked<T>(&mut self) -> &mut T {
671        self.ptr.cast::<T>().as_mut()
672    }
673
674    /// Cast this pointer to a mutable reference.
675    /// # Safety
676    /// You must uphold all safety requirements of [`NonNull::as_mut()`].
677    pub unsafe fn cast_into_mut_unchecked<T>(self) -> &'pointer mut T {
678        self.ptr.cast::<T>().as_mut()
679    }
680
681    /// Cast this pointer to a reference to a type with a matching [`Schema`].
682    ///
683    /// # Panics
684    ///
685    /// Panics if the schema of the pointer does not match that of the type you are casting to.
686    #[track_caller]
687    pub fn cast_mut<T: HasSchema + 'static>(&mut self) -> &mut T {
688        self.try_cast_mut().expect(SchemaMismatchError::MSG)
689    }
690
691    /// Cast this pointer to a mutable reference to a type with a matching [`Schema`].
692    ///
693    /// # Errors
694    /// Errors if the schema of the pointer does not match that of the type you are casting to.
695    pub fn try_cast_mut<T: HasSchema>(&mut self) -> Result<&mut T, SchemaMismatchError> {
696        if self.schema.represents(T::schema()) {
697            // SOUND: this pointer has the same memory representation as T.
698            unsafe { Ok(self.ptr.cast::<T>().as_mut()) }
699        } else {
700            Err(SchemaMismatchError)
701        }
702    }
703
704    /// Cast this pointer to a mutable reference to a type with a matching [`Schema`]. This is
705    /// different than `try_cast` because it consumes the [`SchemaRefMut`] and allows you to, for
706    /// instance, pass it out of a mapping operation without keeping a reference to the old
707    /// [`SchemaRefMut`].
708    ///
709    /// # Panics
710    /// Panics if the schema of the pointer does not match that of the type you are casting to.
711    #[inline]
712    pub fn cast_into_mut<T: HasSchema>(self) -> &'pointer mut T {
713        self.try_cast_into_mut().unwrap()
714    }
715
716    /// Cast this pointer to a mutable reference to a type with a matching [`Schema`]. This is
717    /// different than `try_cast` because it consumes the [`SchemaRefMut`] and allows you to, for
718    /// instance, pass it out of a mapping operation without keeping a reference to the old
719    /// [`SchemaRefMut`].
720    ///
721    /// # Errors
722    /// Errors if the schema of the pointer does not match that of the type you are casting to.
723    pub fn try_cast_into_mut<T: HasSchema>(self) -> Result<&'pointer mut T, SchemaMismatchError> {
724        if self.schema.represents(T::schema()) {
725            // SOUND: We've checked that the pointer represents T
726            Ok(unsafe { self.ptr.cast::<T>().as_mut() })
727        } else {
728            Err(SchemaMismatchError)
729        }
730    }
731
732    /// Create a new [`SchemaRefMut`] from a reference to a type that implements [`HasSchema`].
733    pub fn new<T: HasSchema>(v: &'pointer mut T) -> SchemaRefMut<'pointer> {
734        let schema = T::schema();
735        SchemaRefMut {
736            // SOUND: the &mut T reference cannot be null.
737            ptr: unsafe { NonNull::new_unchecked(v as *mut T as *mut c_void) },
738            schema,
739            _phantom: PhantomData,
740        }
741    }
742
743    /// Create a new [`SchemaRefMut`] from a raw pointer and it's schema.
744    ///
745    /// # Safety
746    /// - The pointee of `ptr` must be accurately described by the given `schema`.
747    /// - `inner` must have correct provenance to allow reads and writes of the pointee type.
748    /// - The pointer must be valid for the full lifetime of this [`SchemaRef`].
749    pub unsafe fn from_ptr_schema(
750        ptr: *mut c_void,
751        schema: &'static Schema,
752    ) -> SchemaRefMut<'pointer> {
753        Self {
754            ptr: NonNull::new_unchecked(ptr),
755            schema,
756            _phantom: PhantomData,
757        }
758    }
759
760    /// Borrow the schema ref as a [`SchemaMap`] if it is one.
761    pub fn into_map(self) -> Result<&'pointer mut SchemaMap, Self> {
762        matches!(self.schema.kind, SchemaKind::Map { .. })
763            // SOUND: Schema asserts this is a schema map
764            .then(|| unsafe { &mut *(self.ptr.as_ptr() as *mut SchemaMap) })
765            .ok_or(self)
766    }
767
768    /// Borrow the schema ref as a [`SchemaVec`] if it is one.
769    pub fn into_vec(self) -> Result<&'pointer mut SchemaVec, Self> {
770        matches!(self.schema.kind, SchemaKind::Vec(_))
771            // SOUND: Schema asserts this is a schema map
772            .then(|| unsafe { &mut *(self.ptr.as_ptr() as *mut SchemaVec) })
773            .ok_or(self)
774    }
775
776    /// Borrow the schema ref as a [`SchemaBox`] if it is one.
777    pub fn into_box(self) -> Result<SchemaRefMut<'pointer>, Self> {
778        matches!(self.schema.kind, SchemaKind::Vec(_))
779            // SOUND: Schema asserts this is a schema box
780            .then(|| unsafe { (*(self.ptr.as_ptr() as *mut SchemaBox)).as_mut() })
781            .ok_or(self)
782    }
783
784    /// Convert into an accessor for the inner data.
785    pub fn into_access_mut(self) -> SchemaRefMutAccess<'pointer> {
786        SchemaRefMutAccess::new(self)
787    }
788
789    /// Get a mutable access helper to this reference.
790    pub fn access_mut(&mut self) -> SchemaRefMutAccess<'_> {
791        SchemaRefMutAccess::new_borrowed(self)
792    }
793
794    /// Get the raw pointer
795    pub fn as_ptr(&self) -> *mut c_void {
796        self.ptr.as_ptr()
797    }
798
799    /// Get the [`Schema`] for the pointer.
800    pub fn schema(&self) -> &'static Schema {
801        self.schema
802    }
803
804    /// Get the hash of this schema box, if supported.
805    pub fn hash(&self) -> Option<u64> {
806        self.schema
807            .hash_fn
808            .as_ref()
809            .map(|hash_fn| unsafe { (hash_fn.get())(self.ptr.as_ptr()) })
810    }
811
812    /// Borrow this [`SchemaRefMut`] as a [`SchemaRef`].
813    pub fn as_ref(&self) -> SchemaRef<'_> {
814        SchemaRef {
815            ptr: self.ptr,
816            schema: self.schema,
817            _phantom: PhantomData,
818        }
819    }
820
821    /// Convert a borrowed [`SchemaRefMut`] to an owned [`SchemaRefMut`] with a lifetime matching
822    /// That of the borrow.
823    pub fn reborrow(&mut self) -> SchemaRefMut<'_> {
824        SchemaRefMut {
825            ptr: self.ptr,
826            schema: self.schema,
827            _phantom: PhantomData,
828        }
829    }
830
831    /// Get the reference to a field.
832    pub fn field<'a, I: Into<FieldIdx<'a>>>(&mut self, field_idx: I) -> Option<SchemaRefMut<'_>> {
833        Some(
834            self.access_mut()
835                .field(field_idx)
836                .ok()?
837                .into_schema_ref_mut(),
838        )
839    }
840
841    /// Get the field pointed to by the given path.
842    pub fn field_path<'a, I: IntoIterator<Item = FieldIdx<'a>>>(
843        &mut self,
844        path: I,
845    ) -> Option<SchemaRefMut<'_>> {
846        self.access_mut()
847            .field_path(path)
848            .map(|x| x.into_schema_ref_mut())
849    }
850
851    /// Get the field pointed to by the given path.
852    pub fn into_field_path<'a, I: IntoIterator<Item = FieldIdx<'a>>>(
853        self,
854        path: I,
855    ) -> Option<Self> {
856        self.into_access_mut()
857            .field_path(path)
858            .map(|x| x.into_schema_ref_mut())
859    }
860
861    /// Get the reference to a field.
862    pub fn into_field<'a, I: Into<FieldIdx<'a>>>(
863        self,
864        field_idx: I,
865    ) -> Result<SchemaRefMut<'pointer>, Self> {
866        self.into_access_mut()
867            .field(field_idx)
868            .map(|x| x.into_schema_ref_mut())
869            .map_err(|access| access.into_schema_ref_mut())
870    }
871
872    /// Clone `other` and write it's data to `self`. Panics if this schema doesn't support cloning.
873    pub fn write(&mut self, other: SchemaRef) -> Result<(), SchemaMismatchError> {
874        if self.schema == other.schema {
875            let clone_fn = self.schema.clone_fn.as_ref().unwrap_or_else(|| {
876                panic!(
877                    "Schema does not provide clone fn: {}",
878                    self.schema.full_name
879                )
880            });
881            // SOUND: we've verified the clone fn matches the schema of both values.
882            unsafe { clone_fn.get()(other.as_ptr(), self.as_ptr()) }
883            Ok(())
884        } else {
885            Err(SchemaMismatchError)
886        }
887    }
888}
889
890/// Access a schema
891pub enum SchemaRefMutAccess<'a> {
892    /// Access a struct.
893    Struct(StructRefMutAccess<'a>),
894    /// Access a vec.
895    Vec(SchemaVecMutAccess<'a>),
896    /// Access an enum.
897    Enum(EnumRefMutAccess<'a>),
898    /// Access a map.
899    Map(SchemaMapMutAccess<'a>),
900    /// Access a struct.
901    Primitive(PrimitiveRefMut<'a>),
902}
903
904/// Mutable [`SchemaVec`] access helper.
905#[derive(Deref, DerefMut)]
906pub struct SchemaVecMutAccess<'a> {
907    /// The schema vec borrow.
908    #[deref]
909    vec: &'a mut SchemaVec,
910    /// The original pointer and schema to allow us to convert back to a [`SchemaRefMut`]
911    /// WARNING: This pointer aliases with the `vec: &'a SchemaVec` reference and mut not be used
912    /// until the borrow to the schema vec is dropped.
913    orig_ptr: *mut c_void,
914    orig_schema: &'static Schema,
915}
916
917impl<'a> SchemaVecMutAccess<'a> {
918    /// Convert back to a [`SchemaRefMut`]
919    pub fn as_mut(self) -> SchemaRefMut<'a> {
920        // SOUND: we are taking ownership of self and dropping the reference that aliases,
921        // so that we can return a valid [`SchemaRefMut`].
922        unsafe { SchemaRefMut::from_ptr_schema(self.orig_ptr, self.orig_schema) }
923    }
924}
925
926/// Mutable [`SchemaMap`] access helper.
927#[derive(Deref, DerefMut)]
928pub struct SchemaMapMutAccess<'a> {
929    /// The schema map borrow.
930    #[deref]
931    map: &'a mut SchemaMap,
932    /// The original pointer and schema to allow us to convert back to a [`SchemaRefMut`]
933    /// WARNING: This pointer aliases with the `vec: &'a SchemaVec` reference and mut not be used
934    /// until the borrow to the schema vec is dropped.
935    orig_ptr: *mut c_void,
936    orig_schema: &'static Schema,
937}
938
939impl<'a> SchemaMapMutAccess<'a> {
940    /// Convert back to a [`SchemaRefMut`]
941    pub fn into_schema_ref_mut(self) -> SchemaRefMut<'a> {
942        // SOUND: we are taking ownership of self and dropping the reference that aliases,
943        // so that we can return a valid [`SchemaRefMut`].
944        unsafe { SchemaRefMut::from_ptr_schema(self.orig_ptr, self.orig_schema) }
945    }
946}
947
948impl std::fmt::Debug for SchemaRefMutAccess<'_> {
949    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
950        self.as_ref().fmt(f)
951    }
952}
953
954impl<'pointer> SchemaRefMutAccess<'pointer> {
955    /// Create a new [`SchemaRefAccess`] for the given [`SchemaRef`].
956    ///
957    /// This will create a new independent [`SchemaRefAccess`] that may be used even after
958    /// the original [`SchemaRef`] is dropped ( but not beyond the safe lifetime of the
959    /// original schema ref ).
960    pub fn new(value: SchemaRefMut) -> SchemaRefMutAccess {
961        match &value.schema.kind {
962            SchemaKind::Struct(_) => SchemaRefMutAccess::Struct(StructRefMutAccess(value)),
963            SchemaKind::Vec(_) => SchemaRefMutAccess::Vec(SchemaVecMutAccess {
964                orig_ptr: value.as_ptr(),
965                orig_schema: value.schema,
966                vec: value.into_vec().unwrap(),
967            }),
968            SchemaKind::Enum(_) => SchemaRefMutAccess::Enum(EnumRefMutAccess(value)),
969            SchemaKind::Map { .. } => SchemaRefMutAccess::Map(SchemaMapMutAccess {
970                orig_ptr: value.as_ptr(),
971                orig_schema: value.schema,
972                map: value.into_map().unwrap(),
973            }),
974            SchemaKind::Box(_) => value.into_box().unwrap().into_access_mut(),
975            SchemaKind::Primitive(_) => SchemaRefMutAccess::Primitive(value.into()),
976        }
977    }
978
979    /// Create a new [`SchemaRefAccess`] for the given [`SchemaRef`] that borrows the original
980    /// [`SchemaRef`].
981    ///
982    /// This is subtly different from [`SchemaRefAccess::new()`] because it requires that it hold
983    /// a borrow to the original schema ref it was created from. This is specifically useful becuse
984    /// it lets you create a [`SchemaRefAccess`] from a refeence to a schema ref, which is required
985    /// when accessing a schema ref that is behind an atomic resource borrow, for example.
986    pub fn new_borrowed<'borrow>(
987        value: &'borrow mut SchemaRefMut<'_>,
988    ) -> SchemaRefMutAccess<'borrow> {
989        match &value.schema.kind {
990            SchemaKind::Struct(_) => {
991                SchemaRefMutAccess::Struct(StructRefMutAccess(value.reborrow()))
992            }
993            SchemaKind::Vec(_) => SchemaRefMutAccess::Vec(SchemaVecMutAccess {
994                orig_ptr: value.as_ptr(),
995                orig_schema: value.schema,
996                vec: value.reborrow().into_vec().unwrap(),
997            }),
998            SchemaKind::Enum(_) => SchemaRefMutAccess::Enum(EnumRefMutAccess(value.reborrow())),
999            SchemaKind::Map { .. } => SchemaRefMutAccess::Map(SchemaMapMutAccess {
1000                orig_ptr: value.as_ptr(),
1001                orig_schema: value.schema,
1002                map: value.reborrow().into_map().unwrap(),
1003            }),
1004            SchemaKind::Box(_) => value.reborrow().into_box().unwrap().into_access_mut(),
1005            SchemaKind::Primitive(_) => SchemaRefMutAccess::Primitive(value.reborrow().into()),
1006        }
1007    }
1008
1009    /// Convert this to a [`SchemaRefMut`].
1010    pub fn into_schema_ref_mut(self) -> SchemaRefMut<'pointer> {
1011        match self {
1012            SchemaRefMutAccess::Struct(s) => s.0,
1013            SchemaRefMutAccess::Vec(v) => v.as_mut(),
1014            SchemaRefMutAccess::Enum(e) => e.0,
1015            SchemaRefMutAccess::Map(m) => m.into_schema_ref_mut(),
1016            SchemaRefMutAccess::Primitive(p) => p.into_schema_ref_mut(),
1017        }
1018    }
1019
1020    /// Get field with the given index.
1021    pub fn field<'a, I: Into<FieldIdx<'a>>>(self, field_idx: I) -> Result<Self, Self> {
1022        let field_idx = field_idx.into();
1023        match self {
1024            SchemaRefMutAccess::Struct(s) => {
1025                s.into_field(field_idx).map_err(SchemaRefMutAccess::Struct)
1026            }
1027            other @ (SchemaRefMutAccess::Vec(_)
1028            | SchemaRefMutAccess::Enum(_)
1029            | SchemaRefMutAccess::Map(_)
1030            | SchemaRefMutAccess::Primitive(_)) => Err(other),
1031        }
1032    }
1033
1034    /// Get the field pointed to by the given path.
1035    pub fn field_path<'a, I: IntoIterator<Item = FieldIdx<'a>>>(self, path: I) -> Option<Self> {
1036        let mut current_field = self;
1037        for field_idx in path {
1038            current_field = current_field.field(field_idx).ok()?;
1039        }
1040        Some(current_field)
1041    }
1042
1043    /// Borrow this [`SchemaRefMutAccess`] as a [`SchemaRefAccess`].
1044    pub fn as_ref(&self) -> SchemaRefAccess<'_> {
1045        match self {
1046            SchemaRefMutAccess::Struct(s) => SchemaRefAccess::Struct(StructRefAccess(s.0.as_ref())),
1047            SchemaRefMutAccess::Vec(v) => SchemaRefAccess::Vec(SchemaVecAccess {
1048                vec: &*v.vec,
1049                // SOUND: We hold an exclusive borrow which we are allowed to downgrade to a read-only reference.
1050                orig_ref: unsafe {
1051                    SchemaRef::from_ptr_schema(
1052                        (&*v.vec) as *const SchemaVec as *const c_void,
1053                        v.orig_schema,
1054                    )
1055                },
1056            }),
1057            SchemaRefMutAccess::Enum(e) => SchemaRefAccess::Enum(EnumRefAccess(e.0.as_ref())),
1058            SchemaRefMutAccess::Map(m) => SchemaRefAccess::Map(SchemaMapAccess {
1059                map: &*m.map,
1060                // SOUND: We hold an exclusive borrow which we are allowed to downgrade to a read-only reference.
1061                orig_ref: unsafe {
1062                    SchemaRef::from_ptr_schema(
1063                        (&*m.map) as *const SchemaMap as *const c_void,
1064                        m.orig_schema,
1065                    )
1066                },
1067            }),
1068            SchemaRefMutAccess::Primitive(p) => SchemaRefAccess::Primitive(p.as_ref()),
1069        }
1070    }
1071}
1072
1073/// Helper for accessing the inner data of a schema ref at runtime.
1074pub struct StructRefMutAccess<'a>(pub SchemaRefMut<'a>);
1075
1076impl<'a> StructRefMutAccess<'a> {
1077    /// Get the struct's schema.
1078    pub fn schema(&self) -> &'static Schema {
1079        self.0.schema
1080    }
1081
1082    /// Get the [`StructSchemaInfo`] for this struct.
1083    pub fn info(&self) -> &'static StructSchemaInfo {
1084        self.0.schema.kind.as_struct().unwrap()
1085    }
1086
1087    /// Access a field, if it exists.
1088    pub fn into_field<'i, I: Into<FieldIdx<'i>>>(
1089        self,
1090        field_idx: I,
1091    ) -> Result<SchemaRefMutAccess<'a>, Self> {
1092        let field_idx = field_idx.into();
1093        let field_idx = match field_idx {
1094            FieldIdx::Name(name) => {
1095                if let Some(idx) = self
1096                    .info()
1097                    .fields
1098                    .iter()
1099                    .position(|x| x.name.as_ref().map(|x| x.as_ref()) == Some(name))
1100                {
1101                    idx
1102                } else {
1103                    return Err(self);
1104                }
1105            }
1106            FieldIdx::Idx(idx) => idx,
1107        };
1108        let field_schema = self
1109            .0
1110            .schema
1111            .kind
1112            .as_struct()
1113            .unwrap()
1114            .fields
1115            .get(field_idx)
1116            .unwrap()
1117            .schema;
1118        let (_, field_offset) = self.0.schema.field_offsets().get(field_idx).unwrap();
1119
1120        Ok(unsafe {
1121            SchemaRefMut {
1122                ptr: NonNull::new_unchecked(self.0.as_ptr().add(*field_offset)),
1123                schema: field_schema,
1124                _phantom: PhantomData,
1125            }
1126            .into_access_mut()
1127        })
1128    }
1129
1130    /// Iterate over fields in the struct.
1131    pub fn fields(&mut self) -> StructRefMutFieldIter<'_> {
1132        StructRefMutFieldIter {
1133            ptr: self.0.reborrow(),
1134            field_idx: 0,
1135        }
1136    }
1137
1138    /// Consume to create an iterator over fields in the struct.
1139    pub fn into_fields(self) -> StructRefMutFieldIter<'a> {
1140        StructRefMutFieldIter {
1141            ptr: self.0,
1142            field_idx: 0,
1143        }
1144    }
1145}
1146
1147/// Iterator for [`StructRefAccess::fields()`].
1148pub struct StructRefMutFieldIter<'a> {
1149    ptr: SchemaRefMut<'a>,
1150    field_idx: usize,
1151}
1152
1153/// A field returned by [`StructRefFieldIter`].
1154pub struct StructRefMutFieldIterField<'a> {
1155    /// The name of the field, if set.
1156    pub name: Option<&'static str>,
1157    /// The field's value.
1158    pub value: SchemaRefMut<'a>,
1159}
1160
1161impl<'a> Iterator for StructRefMutFieldIter<'a> {
1162    type Item = StructRefMutFieldIterField<'a>;
1163
1164    fn next(&mut self) -> Option<Self::Item> {
1165        let field_schema = self
1166            .ptr
1167            .schema
1168            .kind
1169            .as_struct()
1170            .unwrap()
1171            .fields
1172            .get(self.field_idx)?
1173            .schema;
1174        let (name, field_offset) = self.ptr.schema.field_offsets().get(self.field_idx)?;
1175        self.field_idx += 1;
1176
1177        Some(StructRefMutFieldIterField {
1178            name: name.as_ref().map(|x| x.as_str()),
1179            // SOUND: Return a new SchemaRefMut with the 'a lifetime. This is sound because we
1180            // don't return mutliple `SchemaRefMut`s to the same data.
1181            value: unsafe {
1182                SchemaRefMut {
1183                    ptr: NonNull::new_unchecked(self.ptr.as_ptr().add(*field_offset)),
1184                    schema: field_schema,
1185                    _phantom: PhantomData,
1186                }
1187            },
1188        })
1189    }
1190}
1191
1192/// Helper for accessing the inner data of a schema ref at runtime.
1193pub struct EnumRefMutAccess<'a>(pub SchemaRefMut<'a>);
1194
1195impl<'a> EnumRefMutAccess<'a> {
1196    /// Get the enum's schema.
1197    pub fn schema(&self) -> &'static Schema {
1198        self.0.schema
1199    }
1200
1201    /// Get the enum schema info.
1202    pub fn info(&self) -> &'static EnumSchemaInfo {
1203        let SchemaKind::Enum(info) = &self.0.schema.kind else {
1204            panic!("Not an enum");
1205        };
1206        info
1207    }
1208
1209    /// Get the currently-selected variant index.
1210    pub fn variant_idx(&self) -> u32 {
1211        let info = self.info();
1212        match info.tag_type {
1213            EnumTagType::U8 => unsafe { self.0.as_ptr().cast::<u8>().read() as u32 },
1214            EnumTagType::U16 => unsafe { self.0.as_ptr().cast::<u16>().read() as u32 },
1215            EnumTagType::U32 => unsafe { self.0.as_ptr().cast::<u32>().read() },
1216        }
1217    }
1218
1219    /// Get the name of the currently selected variant.
1220    pub fn variant_name(&self) -> &'static str {
1221        let info = self.info();
1222        let idx = self.variant_idx();
1223        info.variants[idx as usize].name.as_ref()
1224    }
1225
1226    /// Get a reference to the enum's currently selected value.
1227    pub fn value(&self) -> StructRefMutAccess<'a> {
1228        let info = self.info();
1229        let variant_idx = self.variant_idx();
1230        let variant_info = &info.variants[variant_idx as usize];
1231        let schema = variant_info.schema;
1232        let value_offset = self.0.schema.field_offsets()[0].1;
1233        StructRefMutAccess(SchemaRefMut {
1234            ptr: unsafe { NonNull::new_unchecked(self.0.ptr.as_ptr().add(value_offset)) },
1235            schema,
1236            _phantom: PhantomData,
1237        })
1238    }
1239}
1240
1241/// Helper for accessing the inner data of a schema ref at runtime.
1242pub enum PrimitiveRefMut<'a> {
1243    /// A [`bool`]
1244    Bool(&'a mut bool),
1245    /// A [`u8`]
1246    U8(&'a mut u8),
1247    /// A [`u16`]
1248    U16(&'a mut u16),
1249    /// A [`u32`]
1250    U32(&'a mut u32),
1251    /// A [`u64`]
1252    U64(&'a mut u64),
1253    /// A [`u128`]
1254    U128(&'a mut u128),
1255    /// An [`i8`]
1256    I8(&'a mut i8),
1257    /// An [`i16`]
1258    I16(&'a mut i16),
1259    /// An [`i32`]
1260    I32(&'a mut i32),
1261    /// An [`i64`]
1262    I64(&'a mut i64),
1263    /// An [`i128`]
1264    I128(&'a mut i128),
1265    /// An [`f32`]
1266    F32(&'a mut f32),
1267    /// An [`f64`]
1268    F64(&'a mut f64),
1269    /// A [`String`]
1270    String(&'a mut String),
1271    /// An opaque type
1272    Opaque {
1273        /// The size of the opaque type.
1274        size: usize,
1275        /// The align of the opaque type.
1276        align: usize,
1277        /// The schema ref.
1278        schema_ref: SchemaRefMut<'a>,
1279    },
1280}
1281
1282impl<'ptr> PrimitiveRefMut<'ptr> {
1283    /// Convert to an immutable [`PrimitiveRef`].
1284    pub fn as_ref(&self) -> PrimitiveRef<'_> {
1285        match self {
1286            PrimitiveRefMut::Bool(b) => PrimitiveRef::Bool(b),
1287            PrimitiveRefMut::U8(n) => PrimitiveRef::U8(n),
1288            PrimitiveRefMut::U16(n) => PrimitiveRef::U16(n),
1289            PrimitiveRefMut::U32(n) => PrimitiveRef::U32(n),
1290            PrimitiveRefMut::U64(n) => PrimitiveRef::U64(n),
1291            PrimitiveRefMut::U128(n) => PrimitiveRef::U128(n),
1292            PrimitiveRefMut::I8(n) => PrimitiveRef::I8(n),
1293            PrimitiveRefMut::I16(n) => PrimitiveRef::I16(n),
1294            PrimitiveRefMut::I32(n) => PrimitiveRef::I32(n),
1295            PrimitiveRefMut::I64(n) => PrimitiveRef::I64(n),
1296            PrimitiveRefMut::I128(n) => PrimitiveRef::I128(n),
1297            PrimitiveRefMut::F32(n) => PrimitiveRef::F32(n),
1298            PrimitiveRefMut::F64(n) => PrimitiveRef::F64(n),
1299            PrimitiveRefMut::String(n) => PrimitiveRef::String(n),
1300            PrimitiveRefMut::Opaque {
1301                size,
1302                align,
1303                schema_ref,
1304            } => PrimitiveRef::Opaque {
1305                size: *size,
1306                align: *align,
1307                schema_ref: schema_ref.as_ref(),
1308            },
1309        }
1310    }
1311
1312    fn into_schema_ref_mut(self) -> SchemaRefMut<'ptr> {
1313        match self {
1314            PrimitiveRefMut::Bool(b) => SchemaRefMut::new(b),
1315            PrimitiveRefMut::U8(n) => SchemaRefMut::new(n),
1316            PrimitiveRefMut::U16(n) => SchemaRefMut::new(n),
1317            PrimitiveRefMut::U32(n) => SchemaRefMut::new(n),
1318            PrimitiveRefMut::U64(n) => SchemaRefMut::new(n),
1319            PrimitiveRefMut::U128(n) => SchemaRefMut::new(n),
1320            PrimitiveRefMut::I8(n) => SchemaRefMut::new(n),
1321            PrimitiveRefMut::I16(n) => SchemaRefMut::new(n),
1322            PrimitiveRefMut::I32(n) => SchemaRefMut::new(n),
1323            PrimitiveRefMut::I64(n) => SchemaRefMut::new(n),
1324            PrimitiveRefMut::I128(n) => SchemaRefMut::new(n),
1325            PrimitiveRefMut::F32(n) => SchemaRefMut::new(n),
1326            PrimitiveRefMut::F64(n) => SchemaRefMut::new(n),
1327            PrimitiveRefMut::String(s) => SchemaRefMut::new(s),
1328            PrimitiveRefMut::Opaque { schema_ref, .. } => schema_ref,
1329        }
1330    }
1331}
1332
1333impl<'a> From<SchemaRefMut<'a>> for PrimitiveRefMut<'a> {
1334    fn from(value: SchemaRefMut<'a>) -> Self {
1335        match &value.schema.kind {
1336            SchemaKind::Primitive(p) => match p {
1337                Primitive::Bool => PrimitiveRefMut::Bool(value.cast_into_mut()),
1338                Primitive::U8 => PrimitiveRefMut::U8(value.cast_into_mut()),
1339                Primitive::U16 => PrimitiveRefMut::U16(value.cast_into_mut()),
1340                Primitive::U32 => PrimitiveRefMut::U32(value.cast_into_mut()),
1341                Primitive::U64 => PrimitiveRefMut::U64(value.cast_into_mut()),
1342                Primitive::U128 => PrimitiveRefMut::U128(value.cast_into_mut()),
1343                Primitive::I8 => PrimitiveRefMut::I8(value.cast_into_mut()),
1344                Primitive::I16 => PrimitiveRefMut::I16(value.cast_into_mut()),
1345                Primitive::I32 => PrimitiveRefMut::I32(value.cast_into_mut()),
1346                Primitive::I64 => PrimitiveRefMut::I64(value.cast_into_mut()),
1347                Primitive::I128 => PrimitiveRefMut::I128(value.cast_into_mut()),
1348                Primitive::F32 => PrimitiveRefMut::F32(value.cast_into_mut()),
1349                Primitive::F64 => PrimitiveRefMut::F64(value.cast_into_mut()),
1350                Primitive::String => PrimitiveRefMut::String(value.cast_into_mut()),
1351                Primitive::Opaque { size, align } => PrimitiveRefMut::Opaque {
1352                    size: *size,
1353                    align: *align,
1354                    schema_ref: value,
1355                },
1356            },
1357            _ => panic!("Schema mismatch"),
1358        }
1359    }
1360}
1361
1362/// A owning, type-erased [`Box`]-like container for types with a [`Schema`].
1363pub struct SchemaBox {
1364    ptr: NonNull<c_void>,
1365    schema: &'static Schema,
1366}
1367impl Default for SchemaBox {
1368    fn default() -> Self {
1369        SchemaBox::new(())
1370    }
1371}
1372unsafe impl Sync for SchemaBox {}
1373unsafe impl Send for SchemaBox {}
1374impl std::fmt::Debug for SchemaBox {
1375    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1376        f.debug_struct("SchemaBox")
1377            .field("schema", &self.schema.full_name)
1378            .field("value", &SchemaRefValueDebug(self.as_ref()))
1379            .finish_non_exhaustive()
1380    }
1381}
1382impl std::fmt::Display for SchemaBox {
1383    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1384        self.as_ref().fmt(f)
1385    }
1386}
1387
1388impl Hash for SchemaBox {
1389    #[track_caller]
1390    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1391        let Some(hash_fn) = &self.schema.hash_fn else {
1392            panic!("Cannot hash schema box where schema doesn't provide hash_fn");
1393        };
1394        let hash = unsafe { (hash_fn.get())(self.ptr.as_ptr()) };
1395        state.write_u64(hash);
1396    }
1397}
1398
1399impl PartialEq for SchemaBox {
1400    fn eq(&self, other: &Self) -> bool {
1401        if self.schema != other.schema {
1402            panic!("Cannot compare two `SchemaBox`s with different schemas.");
1403        }
1404        let Some(eq_fn) = &self.schema.eq_fn else {
1405            panic!("Cannot hash schema box where schema doesn't provide hash_fn.");
1406        };
1407        unsafe { (eq_fn.get())(self.ptr.as_ptr(), other.ptr.as_ptr()) }
1408    }
1409}
1410impl Eq for SchemaBox {}
1411
1412impl Clone for SchemaBox {
1413    fn clone(&self) -> Self {
1414        let clone_fn = self.schema.clone_fn.as_ref().unwrap_or_else(|| {
1415            panic!(
1416                "The schema for this type does not allow cloning it.\nSchema: {:#?}",
1417                self.schema
1418            )
1419        });
1420
1421        let layout = self.schema.layout();
1422        let new_ptr = if layout.size() == 0 {
1423            NonNull::<c_void>::dangling().as_ptr()
1424        } else {
1425            // SOUND: Non-zero size for layout
1426            unsafe { std::alloc::alloc(layout) as *mut c_void }
1427        };
1428        let new_ptr = unsafe {
1429            (clone_fn.get())(self.ptr.as_ptr(), new_ptr);
1430            NonNull::new(new_ptr).unwrap_or_else(|| handle_alloc_error(layout))
1431        };
1432        Self {
1433            ptr: new_ptr,
1434            schema: self.schema,
1435        }
1436    }
1437}
1438
1439impl SchemaBox {
1440    /// Get a raw pointer to the box data.
1441    pub fn as_ptr(&self) -> *mut c_void {
1442        self.ptr.as_ptr()
1443    }
1444
1445    /// Cast this box to it's inner type and return it.
1446    /// # Panics
1447    /// Panics if the schema of the box does not match that of the type you are casting to.
1448    #[track_caller]
1449    pub fn cast_into<T: HasSchema>(self) -> T {
1450        self.try_cast_into().unwrap()
1451    }
1452
1453    /// Cast this box to it's inner type and return it.
1454    /// # Errors
1455    /// Errors if the schema of the box does not match that of the type you are casting to.
1456    pub fn try_cast_into<T: HasSchema>(self) -> Result<T, SchemaMismatchError> {
1457        if self.schema == T::schema() {
1458            // We've validated that the schema of the box matches T
1459            Ok(unsafe { self.cast_into_unchecked() })
1460        } else {
1461            Err(SchemaMismatchError)
1462        }
1463    }
1464
1465    /// Unsafely convert this box into an owned T.
1466    /// # Safety
1467    /// - The schema of type T must equal that of this box.
1468    pub unsafe fn cast_into_unchecked<T: HasSchema>(self) -> T {
1469        // Allocate memory for T on the stack
1470        let mut ret = MaybeUninit::<T>::uninit();
1471
1472        // Copy the data from the box into the stack.
1473        // SOUND: We've validated that the box has the same schema as T
1474        unsafe {
1475            (ret.as_mut_ptr() as *mut c_void)
1476                .copy_from_nonoverlapping(self.ptr.as_ptr(), self.schema.layout().size());
1477        }
1478
1479        // De-allocate the box without running the destructor for the inner data.
1480        self.forget();
1481
1482        // SOUND: we initialized the type above
1483        unsafe { ret.assume_init() }
1484    }
1485
1486    /// Cast this box to a reference to a type with a representative [`Schema`].
1487    /// # Panics
1488    /// Panics if the schema of the box does not match that of the type you are casting to.
1489    #[track_caller]
1490    pub fn cast_ref<T: HasSchema>(&self) -> &T {
1491        self.try_cast_ref().expect(SchemaMismatchError::MSG)
1492    }
1493
1494    /// Cast this box to a reference to a type with a representative [`Schema`].
1495    /// # Errors
1496    /// Errors if the schema of the box does not match that of the type you are casting to.
1497    pub fn try_cast_ref<T: HasSchema>(&self) -> Result<&T, SchemaMismatchError> {
1498        if self.schema.represents(T::schema()) {
1499            // SOUND: the schemas have the same memory representation.
1500            unsafe { Ok(self.ptr.cast::<T>().as_ref()) }
1501        } else {
1502            Err(SchemaMismatchError)
1503        }
1504    }
1505
1506    /// Cast this box to a mutable reference to a type with a representing [`Schema`].
1507    /// # Panics
1508    /// Panics if the schema of the box does not match that of the type you are casting to.
1509    #[track_caller]
1510    pub fn cast_mut<T: HasSchema>(&mut self) -> &mut T {
1511        self.try_cast_mut().expect(SchemaMismatchError::MSG)
1512    }
1513
1514    /// Cast this box to a mutable reference to a type with a representing [`Schema`].
1515    /// # Errors
1516    /// Errors if the schema of the box does not match that of the type you are casting to.
1517    pub fn try_cast_mut<T: HasSchema>(&mut self) -> Result<&mut T, SchemaMismatchError> {
1518        if self.schema.represents(T::schema()) {
1519            // SOUND: the schemas have the same memory representation.
1520            unsafe { Ok(self.ptr.cast::<T>().as_mut()) }
1521        } else {
1522            Err(SchemaMismatchError)
1523        }
1524    }
1525
1526    /// Borrow this box as a [`SchemaRef`].
1527    pub fn as_ref(&self) -> SchemaRef<'_> {
1528        SchemaRef {
1529            ptr: self.ptr,
1530            schema: self.schema,
1531            _phantom: PhantomData,
1532        }
1533    }
1534
1535    /// Borrow this box as a [`SchemaRefMut`].
1536    pub fn as_mut(&mut self) -> SchemaRefMut<'_> {
1537        SchemaRefMut {
1538            ptr: self.ptr,
1539            schema: self.schema,
1540            _phantom: PhantomData,
1541        }
1542    }
1543
1544    /// Create a new [`SchemaBox`] from an owned type.
1545    #[track_caller]
1546    pub fn new<T: HasSchema + Sync + Send>(v: T) -> Self {
1547        let schema = T::schema();
1548        // SOUND: we initialize the box immediately after creation.
1549        unsafe {
1550            let b = SchemaBox::uninitialized(schema);
1551            (b.ptr.as_ptr() as *mut T).write(v);
1552            b
1553        }
1554    }
1555
1556    /// Allocates a [`SchemaBox`] for the given [`Schema`], but **doesn't initialize the memory**.
1557    ///
1558    /// # Safety
1559    ///
1560    /// Accessing the data in an unitinialized [`SchemaBox`] is undefined behavior. It is up to the
1561    /// user to initialize the memory pointed at by the box after creating it.
1562    pub unsafe fn uninitialized(schema: &'static Schema) -> Self {
1563        let layout = schema.layout();
1564
1565        let ptr = if layout.size() == 0 {
1566            NonNull::<c_void>::dangling().as_ptr()
1567        } else {
1568            // SOUND: Non-zero size for layout
1569            std::alloc::alloc(layout) as *mut c_void
1570        };
1571        // SOUND: The pointer is allocated for the layout matching the schema.
1572        let ptr = NonNull::new(ptr).unwrap_or_else(|| handle_alloc_error(layout));
1573
1574        Self { ptr, schema }
1575    }
1576
1577    /// Create a new [`SchemaBox`] for a type with a [`Schema`] that has a
1578    /// [`SchemaData::default_fn`].
1579    ///
1580    /// # Panics
1581    ///
1582    /// Panics if the passed in schema doesn't have a `default_fn`.
1583    #[track_caller]
1584    pub fn default(schema: &'static Schema) -> Self {
1585        let Some(default_fn) = &schema.default_fn else {
1586            panic!("Schema doesn't have `default_fn` to create default value with.");
1587        };
1588
1589        unsafe {
1590            let b = SchemaBox::uninitialized(schema);
1591            (default_fn.get())(b.ptr.as_ptr());
1592            b
1593        }
1594    }
1595
1596    /// Convert into an [`SBox`] if the schema of T matches.
1597    /// # Panics
1598    /// Panics if the schema of `T` doesn't match that of the box.
1599    pub fn into_sbox<T: HasSchema>(self) -> SBox<T> {
1600        self.try_into_sbox()
1601            .unwrap_or_else(|_| panic!("{:?}", SchemaMismatchError))
1602    }
1603
1604    /// Convert into an [`SBox`] if the schema of T matches.
1605    /// # Errors
1606    /// Returns an error with the orignal [`SchemaBox`] if the schema of `T` doesn't match.
1607    pub fn try_into_sbox<T: HasSchema>(self) -> Result<SBox<T>, Self> {
1608        if self.schema == T::schema() {
1609            Ok(SBox {
1610                b: self,
1611                _phantom: PhantomData,
1612            })
1613        } else {
1614            Err(self)
1615        }
1616    }
1617
1618    /// Get the [`Schema`] for the pointer.
1619    pub fn schema(&self) -> &'static Schema {
1620        self.schema
1621    }
1622
1623    /// Create a new [`SchemaBox`] from raw parts.
1624    ///
1625    /// This is useful for creating a [`SchemaBox`] for data with a schema loaded at runtime and
1626    /// without a Rust type.
1627    ///
1628    /// # Safety
1629    ///
1630    /// - You must insure that the pointer is valid for the given schema.
1631    pub unsafe fn from_raw_parts(ptr: NonNull<c_void>, schema: &'static Schema) -> Self {
1632        Self { ptr, schema }
1633    }
1634
1635    /// Deallocate the memory stored in the box, but don't run the destructor.
1636    pub fn forget(mut self) {
1637        unsafe {
1638            self.dealloc();
1639        }
1640        std::mem::forget(self);
1641    }
1642
1643    /// Get the hash of this schema box, if supported.
1644    pub fn try_hash(&self) -> Option<u64> {
1645        self.schema
1646            .hash_fn
1647            .as_ref()
1648            .map(|hash_fn| unsafe { (hash_fn.get())(self.ptr.as_ptr()) })
1649    }
1650
1651    /// Get the hash of this schema box.
1652    /// # Panics
1653    /// Panics if the schema doesn't implement hash.
1654    #[track_caller]
1655    pub fn hash(&self) -> u64 {
1656        self.try_hash().expect("Schema doesn't implement hash")
1657    }
1658
1659    /// Deallocate the memory in the box.
1660    unsafe fn dealloc(&mut self) {
1661        if self.schema.layout().size() > 0 {
1662            std::alloc::dealloc(self.ptr.as_ptr() as *mut u8, self.schema.layout())
1663        }
1664    }
1665
1666    /// Drop the inner type, without dealocating the box's memory.
1667    unsafe fn drop_inner(&mut self) {
1668        if let Some(drop_fn) = &self.schema.drop_fn {
1669            // Drop the type
1670            (drop_fn.get())(self.ptr.as_ptr());
1671        }
1672    }
1673}
1674
1675unsafe impl HasSchema for SchemaBox {
1676    fn schema() -> &'static Schema {
1677        use crate::raw_fns::*;
1678        use std::alloc::Layout;
1679        static S: OnceLock<&'static Schema> = OnceLock::new();
1680        let layout = Layout::new::<Self>();
1681        S.get_or_init(|| {
1682            SCHEMA_REGISTRY.register(SchemaData {
1683                name: type_name::<Self>().into(),
1684                full_name: format!("{}::{}", module_path!(), type_name::<Self>()).into(),
1685                kind: SchemaKind::Primitive(Primitive::Opaque {
1686                    size: layout.size(),
1687                    align: layout.align(),
1688                }),
1689                type_id: Some(TypeId::of::<Self>()),
1690                clone_fn: Some(<Self as RawClone>::raw_clone_cb()),
1691                drop_fn: Some(<Self as RawDrop>::raw_drop_cb()),
1692                default_fn: None,
1693                hash_fn: Some(<Self as RawHash>::raw_hash_cb()),
1694                eq_fn: Some(<Self as RawEq>::raw_eq_cb()),
1695                type_data: default(),
1696            })
1697        })
1698    }
1699}
1700
1701impl Drop for SchemaBox {
1702    fn drop(&mut self) {
1703        unsafe {
1704            self.drop_inner();
1705            self.dealloc();
1706        }
1707    }
1708}
1709
1710/// A typed version of [`SchemaBox`].
1711///
1712/// This allows to use [`SBox<T>`] extremely similar to a [`Box<T>`] except that it can be converted
1713/// to and from a [`SchemaBox`] for compatibility with the schema ecosystem.
1714///
1715/// Also, compared to a [`SchemaBox`], it is more efficient to access, because it avoids extra
1716/// runtime checks for a matching schema after it has been created, and doesn't need to be cast to
1717/// `T` upon every access.
1718#[repr(transparent)]
1719pub struct SBox<T: HasSchema> {
1720    b: SchemaBox,
1721    _phantom: PhantomData<T>,
1722}
1723impl<T: HasSchema> Default for SBox<T> {
1724    #[track_caller]
1725    fn default() -> Self {
1726        let schema = T::schema();
1727        let Some(default_fn) = &schema.default_fn else {
1728            panic!("Schema doesn't implement default");
1729        };
1730        Self {
1731            // SOUND: we initialize the schema box immediately, and the schema asserts the default
1732            // fn is valid for the type.
1733            b: unsafe {
1734                let mut b = SchemaBox::uninitialized(schema);
1735                (default_fn.get())(b.as_mut().as_ptr());
1736                b
1737            },
1738            _phantom: Default::default(),
1739        }
1740    }
1741}
1742impl<T: HasSchema> Clone for SBox<T> {
1743    fn clone(&self) -> Self {
1744        Self {
1745            b: self.b.clone(),
1746            _phantom: self._phantom,
1747        }
1748    }
1749}
1750impl<T: HasSchema + std::fmt::Debug> std::fmt::Debug for SBox<T> {
1751    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1752        f.debug_struct("SBox").field("b", &self.b).finish()
1753    }
1754}
1755unsafe impl<T: HasSchema> HasSchema for SBox<T> {
1756    fn schema() -> &'static Schema {
1757        static S: OnceLock<RwLock<HashMap<TypeId, &'static Schema>>> = OnceLock::new();
1758        let schema = {
1759            S.get_or_init(default)
1760                .read()
1761                .get(&TypeId::of::<Self>())
1762                .copied()
1763        };
1764        schema.unwrap_or_else(|| {
1765            let schema = SCHEMA_REGISTRY.register(SchemaData {
1766                name: type_name::<Self>().into(),
1767                full_name: format!("{}::{}", module_path!(), type_name::<Self>()).into(),
1768                kind: SchemaKind::Box(T::schema()),
1769                type_id: Some(TypeId::of::<Self>()),
1770                clone_fn: Some(<Self as RawClone>::raw_clone_cb()),
1771                drop_fn: Some(<Self as RawDrop>::raw_drop_cb()),
1772                default_fn: Some(<Self as RawDefault>::raw_default_cb()),
1773                hash_fn: Some(unsafe {
1774                    Unsafe::new(Box::leak(Box::new(|a| SchemaVec::raw_hash(a))))
1775                }),
1776                eq_fn: Some(unsafe {
1777                    Unsafe::new(Box::leak(Box::new(|a, b| SchemaVec::raw_eq(a, b))))
1778                }),
1779                type_data: Default::default(),
1780            });
1781
1782            S.get_or_init(default)
1783                .write()
1784                .insert(TypeId::of::<Self>(), schema);
1785
1786            schema
1787        })
1788    }
1789}
1790
1791impl<T: HasSchema> SBox<T> {
1792    /// Create a new [`SBox`].
1793    pub fn new(value: T) -> Self {
1794        SBox {
1795            b: SchemaBox::new(value),
1796            _phantom: PhantomData,
1797        }
1798    }
1799
1800    /// Convert into a [`SchemaBox`]
1801    pub fn into_schema_box(self) -> SchemaBox {
1802        self.b
1803    }
1804}
1805
1806impl<T: HasSchema> From<SBox<T>> for SchemaBox {
1807    fn from(value: SBox<T>) -> Self {
1808        value.b
1809    }
1810}
1811
1812impl<T: HasSchema> TryFrom<SchemaBox> for SBox<T> {
1813    type Error = SchemaBox;
1814    fn try_from(value: SchemaBox) -> Result<Self, Self::Error> {
1815        value.try_into_sbox()
1816    }
1817}
1818
1819impl<T: HasSchema> std::ops::Deref for SBox<T> {
1820    type Target = T;
1821
1822    fn deref(&self) -> &Self::Target {
1823        // SOUND: `SBox`s always contain their type `T`.
1824        unsafe { self.b.ptr.cast::<T>().as_ref() }
1825    }
1826}
1827impl<T: HasSchema> std::ops::DerefMut for SBox<T> {
1828    fn deref_mut(&mut self) -> &mut Self::Target {
1829        // SOUND: `SBox`s always contain their type `T`.
1830        unsafe { self.b.ptr.cast::<T>().as_mut() }
1831    }
1832}
1833
1834/// The index of a field in a struct in a [`Schema`].
1835#[derive(Debug, Clone, Copy)]
1836pub enum FieldIdx<'a> {
1837    /// The name of a field.
1838    Name(&'a str),
1839    /// The index of a field. Works for tuple fields and named fields.
1840    Idx(usize),
1841}
1842impl From<usize> for FieldIdx<'static> {
1843    fn from(value: usize) -> Self {
1844        Self::Idx(value)
1845    }
1846}
1847impl<'a> From<&'a str> for FieldIdx<'a> {
1848    fn from(value: &'a str) -> Self {
1849        Self::Name(value)
1850    }
1851}
1852impl<'a> From<&'a String> for FieldIdx<'a> {
1853    fn from(value: &'a String) -> Self {
1854        Self::Name(value)
1855    }
1856}
1857impl<'a> std::fmt::Display for FieldIdx<'a> {
1858    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1859        match self {
1860            Self::Idx(i) => write!(f, "{i}"),
1861            Self::Name(n) => write!(f, "{n}"),
1862        }
1863    }
1864}
1865
1866/// A wrapper type that implements [`IntoIterator<Item = FieldIdx>`] for an inner string to make
1867/// it easier to use with [`SchemaRefAccess::field_path()`] and other field path methods.
1868pub struct FieldPath<T>(pub T);
1869impl<'a> IntoIterator for FieldPath<&'a str> {
1870    type Item = FieldIdx<'a>;
1871    type IntoIter = Map<Filter<Split<'a, char>, fn(&&str) -> bool>, fn(&str) -> FieldIdx>;
1872
1873    fn into_iter(self) -> Self::IntoIter {
1874        fn flt(x: &&str) -> bool {
1875            !x.is_empty()
1876        }
1877        fn mp(x: &str) -> FieldIdx<'_> {
1878            x.parse::<usize>()
1879                .map(FieldIdx::Idx)
1880                .unwrap_or(FieldIdx::Name(x))
1881        }
1882        self.0.split('.').filter(flt as _).map(mp as _)
1883    }
1884}
1885impl IntoIterator for FieldPath<Ustr> {
1886    type Item = FieldIdx<'static>;
1887    type IntoIter = Map<Filter<Split<'static, char>, fn(&&str) -> bool>, fn(&str) -> FieldIdx>;
1888
1889    fn into_iter(self) -> Self::IntoIter {
1890        fn flt(x: &&str) -> bool {
1891            !x.is_empty()
1892        }
1893        fn mp(x: &str) -> FieldIdx<'_> {
1894            x.parse::<usize>()
1895                .map(FieldIdx::Idx)
1896                .unwrap_or(FieldIdx::Name(x))
1897        }
1898        self.0.as_str().split('.').filter(flt as _).map(mp as _)
1899    }
1900}
1901
1902/// Error type when attempting to cast between types with mis-matched schemas.
1903#[derive(Debug)]
1904pub struct SchemaMismatchError;
1905impl SchemaMismatchError {
1906    /// The display error message for this error type.
1907    pub const MSG: &'static str =
1908        "Invalid cast: the schemas of the casted types are not compatible.";
1909}
1910impl std::error::Error for SchemaMismatchError {}
1911impl std::fmt::Display for SchemaMismatchError {
1912    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1913        write!(f, "{}", Self::MSG)
1914    }
1915}
1916
1917/// Error returned when a field is not found in a schema.
1918#[derive(Debug)]
1919pub struct SchemaFieldNotFoundError<'a> {
1920    idx: FieldIdx<'a>,
1921}
1922impl<'a> std::error::Error for SchemaFieldNotFoundError<'a> {}
1923impl<'a> std::fmt::Display for SchemaFieldNotFoundError<'a> {
1924    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1925        write!(f, "Field not found in schema: {}", self.idx)
1926    }
1927}