rudy_types/
lib.rs

1//! Definition of types in the Rust language.
2
3use std::{mem::size_of, sync::Arc};
4
5use itertools::Itertools;
6use salsa::Update;
7
8impl Location for () {}
9
10impl<L: Location> Layout<L> {
11    pub fn display_name(&self) -> String {
12        match &self {
13            Layout::Primitive(primitive_def) => match primitive_def {
14                PrimitiveLayout::Array(array_def) => format!(
15                    "[{}; {}]",
16                    array_def.element_type.display_name(),
17                    array_def.length
18                ),
19                PrimitiveLayout::Bool(_) => "bool".to_string(),
20                PrimitiveLayout::Char(_) => "char".to_string(),
21                PrimitiveLayout::Float(float_def) => {
22                    format!("f{}", float_def.size * 8)
23                }
24                PrimitiveLayout::Function(function_def) => function_def.display_name(),
25                PrimitiveLayout::Int(int_def) => int_def.display_name(),
26                PrimitiveLayout::Never(_) => "!".to_string(),
27                PrimitiveLayout::Pointer(pointer_def) => {
28                    format!("*{}", pointer_def.pointed_type.display_name())
29                }
30                PrimitiveLayout::Reference(reference_def) => {
31                    let mut_ref = if reference_def.mutable { "mut " } else { "" };
32                    format!("&{}{}", mut_ref, reference_def.pointed_type.display_name())
33                }
34                PrimitiveLayout::Slice(slice_def) => {
35                    format!("&[{}]", slice_def.element_type.display_name())
36                }
37                PrimitiveLayout::Str(_) => "str".to_string(),
38                PrimitiveLayout::StrSlice(_) => "&str".to_string(),
39                PrimitiveLayout::Tuple(tuple_def) => {
40                    let elements = tuple_def
41                        .elements
42                        .iter()
43                        .map(|(_, element)| element.display_name())
44                        .join(", ");
45                    format!("({elements})")
46                }
47                PrimitiveLayout::Unit(_) => "()".to_string(),
48                PrimitiveLayout::UnsignedInt(unsigned_int_def) => unsigned_int_def.display_name(),
49            },
50            Layout::Std(std_def) => match std_def {
51                StdLayout::SmartPtr(smart_ptr_def) => {
52                    let inner = smart_ptr_def.inner_type.display_name();
53                    match smart_ptr_def.variant {
54                        SmartPtrVariant::Box => format!("Box<{inner}>"),
55                        _ => format!("{:?}<{}>", smart_ptr_def.variant, inner),
56                    }
57                }
58                StdLayout::Map(map_def) => map_def.display_name(),
59                StdLayout::Option(option_def) => {
60                    let inner_type = option_def.some_type.display_name();
61                    format!("Option<{inner_type}>")
62                }
63                StdLayout::Result(result_def) => {
64                    let ok_type = result_def.ok_type.display_name();
65                    let err_type = result_def.err_type.display_name();
66                    format!("Result<{ok_type}, {err_type}>")
67                }
68                StdLayout::String(_) => "String".to_string(),
69                StdLayout::Vec(vec_def) => {
70                    let inner_type = vec_def.inner_type.display_name();
71                    format!("Vec<{inner_type}>")
72                }
73            },
74            Layout::Struct(struct_def) => struct_def.name.clone(),
75            Layout::Enum(enum_def) => enum_def.name.clone(),
76            Layout::CEnum(c_enum_def) => c_enum_def.name.clone(),
77            Layout::Alias { name } => name.to_string(),
78        }
79    }
80
81    pub fn size(&self) -> Option<usize> {
82        match &self {
83            Layout::Primitive(primitive_def) => primitive_def.size(),
84            Layout::Std(std_def) => std_def.size(),
85            Layout::Struct(struct_def) => Some(struct_def.size),
86            Layout::Enum(enum_def) => Some(enum_def.size),
87            Layout::CEnum(c_enum_def) => Some(c_enum_def.size),
88            Layout::Alias { name: _ } => None,
89        }
90    }
91
92    pub fn matching_type(&self, other: &Layout<L>) -> bool {
93        match (self, other) {
94            (Layout::Primitive(p1), Layout::Primitive(p2)) => p1.matching_type(p2),
95            (Layout::Std(s1), Layout::Std(s2)) => s1.matching_type(s2),
96            (Layout::Struct(s1), Layout::Struct(s2)) => s1.name == s2.name,
97            (Layout::Struct(s1), Layout::Alias { name }) => &s1.name == name,
98            (Layout::Alias { name: left }, Layout::Alias { name: right }) => left == right,
99            (Layout::Alias { name }, x) | (x, Layout::Alias { name }) => name == &x.display_name(),
100            (Layout::Enum(e1), Layout::Enum(e2)) => e1.name == e2.name,
101            (Layout::CEnum(e1), Layout::CEnum(e2)) => e1.name == e2.name,
102            _ => false,
103        }
104    }
105
106    pub fn as_reference(&self, location: L) -> Layout<L>
107    where
108        Self: Clone,
109    {
110        Layout::Primitive(PrimitiveLayout::Reference(ReferenceLayout {
111            mutable: false,
112            pointed_type: TypeDefinition::new(location, self.clone()),
113        }))
114    }
115
116    pub fn dereferenced(&self) -> &Layout<L> {
117        match self {
118            Layout::Primitive(PrimitiveLayout::Pointer(pointer_def)) => {
119                pointer_def.pointed_type.layout.dereferenced()
120            }
121            Layout::Primitive(PrimitiveLayout::Reference(reference_def)) => {
122                reference_def.pointed_type.layout.dereferenced()
123            }
124            _ => {
125                // If it's not a pointer or reference, return self
126                self
127            }
128        }
129    }
130}
131
132// Conversion helpers for cleaner test code
133impl<L: Location> From<PrimitiveLayout<L>> for Layout<L> {
134    fn from(primitive: PrimitiveLayout<L>) -> Self {
135        Layout::Primitive(primitive)
136    }
137}
138
139impl<L: Location> From<StdLayout<L>> for Layout<L> {
140    fn from(std_def: StdLayout<L>) -> Self {
141        Layout::Std(std_def)
142    }
143}
144
145impl<L: Location> From<StructLayout<L>> for Layout<L> {
146    fn from(struct_def: StructLayout<L>) -> Self {
147        Layout::Struct(struct_def)
148    }
149}
150
151impl<L: Location> From<EnumLayout<L>> for Layout<L> {
152    fn from(enum_def: EnumLayout<L>) -> Self {
153        Layout::Enum(enum_def)
154    }
155}
156
157// PrimitiveDef conversions
158impl<L: Location> From<ArrayLayout<L>> for PrimitiveLayout<L> {
159    fn from(array: ArrayLayout<L>) -> Self {
160        PrimitiveLayout::Array(array)
161    }
162}
163
164impl<L: Location> From<FloatLayout> for PrimitiveLayout<L> {
165    fn from(float: FloatLayout) -> Self {
166        PrimitiveLayout::Float(float)
167    }
168}
169
170impl<L: Location> From<FunctionLayout<L>> for PrimitiveLayout<L> {
171    fn from(function: FunctionLayout<L>) -> Self {
172        PrimitiveLayout::Function(function)
173    }
174}
175
176impl<L: Location> From<IntLayout> for PrimitiveLayout<L> {
177    fn from(int: IntLayout) -> Self {
178        PrimitiveLayout::Int(int)
179    }
180}
181
182impl<L: Location> From<PointerLayout<L>> for PrimitiveLayout<L> {
183    fn from(pointer: PointerLayout<L>) -> Self {
184        PrimitiveLayout::Pointer(pointer)
185    }
186}
187
188impl<L: Location> From<ReferenceLayout<L>> for PrimitiveLayout<L> {
189    fn from(reference: ReferenceLayout<L>) -> Self {
190        PrimitiveLayout::Reference(reference)
191    }
192}
193
194impl<L: Location> From<SliceLayout<L>> for PrimitiveLayout<L> {
195    fn from(slice: SliceLayout<L>) -> Self {
196        PrimitiveLayout::Slice(slice)
197    }
198}
199
200impl<L: Location> From<StrSliceLayout> for PrimitiveLayout<L> {
201    fn from(str_slice: StrSliceLayout) -> Self {
202        PrimitiveLayout::StrSlice(str_slice)
203    }
204}
205
206impl<L: Location> From<TupleLayout<L>> for PrimitiveLayout<L> {
207    fn from(tuple: TupleLayout<L>) -> Self {
208        PrimitiveLayout::Tuple(tuple)
209    }
210}
211
212impl<L: Location> From<UnitLayout> for PrimitiveLayout<L> {
213    fn from(unit: UnitLayout) -> Self {
214        PrimitiveLayout::Unit(unit)
215    }
216}
217
218impl<L: Location> From<UnsignedIntLayout> for PrimitiveLayout<L> {
219    fn from(uint: UnsignedIntLayout) -> Self {
220        PrimitiveLayout::UnsignedInt(uint)
221    }
222}
223
224// StdDef conversions
225impl<L: Location> From<SmartPtrLayout<L>> for StdLayout<L> {
226    fn from(smart_ptr: SmartPtrLayout<L>) -> Self {
227        StdLayout::SmartPtr(smart_ptr)
228    }
229}
230
231impl<L: Location> From<MapLayout<L>> for StdLayout<L> {
232    fn from(map: MapLayout<L>) -> Self {
233        StdLayout::Map(map)
234    }
235}
236
237impl<L: Location> From<StringLayout<L>> for StdLayout<L> {
238    fn from(string: StringLayout<L>) -> Self {
239        StdLayout::String(string)
240    }
241}
242
243impl<L: Location> From<VecLayout<L>> for StdLayout<L> {
244    fn from(vec: VecLayout<L>) -> Self {
245        StdLayout::Vec(vec)
246    }
247}
248
249// Convenience constructors for primitives with unit values
250impl<L: Location> From<()> for PrimitiveLayout<L> {
251    fn from(_: ()) -> Self {
252        PrimitiveLayout::Bool(())
253    }
254}
255
256// Chain conversions for common patterns
257impl<L: Location> From<UnsignedIntLayout> for Layout<L> {
258    fn from(uint: UnsignedIntLayout) -> Self {
259        Layout::Primitive(PrimitiveLayout::UnsignedInt(uint))
260    }
261}
262
263impl<L: Location> From<IntLayout> for Layout<L> {
264    fn from(int: IntLayout) -> Self {
265        Layout::Primitive(PrimitiveLayout::Int(int))
266    }
267}
268
269impl<L: Location> From<FloatLayout> for Layout<L> {
270    fn from(float: FloatLayout) -> Self {
271        Layout::Primitive(PrimitiveLayout::Float(float))
272    }
273}
274
275impl<L: Location> From<ReferenceLayout<L>> for Layout<L> {
276    fn from(reference: ReferenceLayout<L>) -> Self {
277        Layout::Primitive(PrimitiveLayout::Reference(reference))
278    }
279}
280
281impl<L: Location> From<StringLayout<L>> for Layout<L> {
282    fn from(string: StringLayout<L>) -> Self {
283        Layout::Std(StdLayout::String(string))
284    }
285}
286
287impl<L: Location> From<VecLayout<L>> for Layout<L> {
288    fn from(vec: VecLayout<L>) -> Self {
289        Layout::Std(StdLayout::Vec(vec))
290    }
291}
292
293impl<L: Location> From<MapLayout<L>> for Layout<L> {
294    fn from(map: MapLayout<L>) -> Self {
295        Layout::Std(StdLayout::Map(map))
296    }
297}
298
299impl<L: Location> From<SmartPtrLayout<L>> for Layout<L> {
300    fn from(smart_ptr: SmartPtrLayout<L>) -> Self {
301        Layout::Std(StdLayout::SmartPtr(smart_ptr))
302    }
303}
304
305#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
306pub struct TypeDefinition<L = ()>
307where
308    L: Location,
309{
310    /// The layout of the type definition
311    ///
312    /// This is an owned reference to the layout,
313    /// so it can be shared across multiple definitions
314    pub layout: Arc<Layout<L>>,
315
316    /// The location of the type definition in the DWARF
317    /// information. This is used to resolve
318    /// the type definition in the debug information.
319    pub location: L,
320}
321
322impl<L> TypeDefinition<L>
323where
324    L: Location,
325{
326    pub fn new(location: L, layout: Layout<L>) -> Self {
327        Self {
328            layout: Arc::new(layout),
329            location,
330        }
331    }
332
333    pub fn display_name(&self) -> String {
334        self.layout.display_name()
335    }
336
337    pub fn size(&self) -> Option<usize> {
338        self.layout.size()
339    }
340
341    pub fn matching_type(&self, other: &Self) -> bool {
342        self.location.matches(&other.location) || self.layout.matching_type(&other.layout)
343    }
344}
345
346pub trait Location: Update {
347    fn matches(&self, _other: &Self) -> bool {
348        // Default implementation for `()` (no location)
349        // This can be overridden by specific location types
350        false
351    }
352}
353
354#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
355pub enum Layout<L = ()>
356where
357    L: Location,
358{
359    /// Language-specific primitive types from `core::primitive`
360    /// (e.g. `i32`, `f64`, etc.)
361    ///
362    /// There are all simple types that can
363    /// be backed by a single slice of memory
364    /// and easily transumted to a Rust type
365    Primitive(PrimitiveLayout<L>),
366
367    /// Common definitions from the Rust standard library
368    Std(StdLayout<L>),
369
370    // Custom type definitions
371    /// Structs and tuples
372    Struct(StructLayout<L>),
373
374    /// Enums
375    Enum(EnumLayout<L>),
376
377    /// C-style enumerations (simple named integer constants)
378    CEnum(CEnumLayout),
379
380    /// Type currently known only by its name
381    Alias { name: String },
382}
383
384/// From the Rust standard library:
385#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
386pub enum PrimitiveLayout<L = ()>
387where
388    L: Location,
389{
390    Array(ArrayLayout<L>),
391    Bool(()),
392    Char(()),
393    Float(FloatLayout),
394    Function(FunctionLayout<L>),
395    Int(IntLayout),
396    Never(()),
397    Pointer(PointerLayout<L>),
398    Reference(ReferenceLayout<L>),
399    Slice(SliceLayout<L>),
400    /// Technically constructable, `str` is like `[u8; N]`
401    /// but where the size is opaque (since utf8 is variable length)
402    /// and so rarely seen in the wild. We could have something like `Box<str>`
403    /// though.
404    Str(()),
405    /// A specialization of `Slice` where the referenced type is `str`
406    /// Also helps us avoid using the `str` type.
407    StrSlice(StrSliceLayout),
408    Tuple(TupleLayout<L>),
409    Unit(UnitLayout),
410    UnsignedInt(UnsignedIntLayout),
411    // neverExperimental,
412}
413
414impl<L: Location> PrimitiveLayout<L> {
415    fn size(&self) -> Option<usize> {
416        let size = match self {
417            PrimitiveLayout::Array(array_def) => {
418                let element_size = array_def.element_type.size()?;
419                element_size * array_def.length
420            }
421            PrimitiveLayout::Bool(_) => {
422                // bool is 1 byte
423                1
424            }
425            PrimitiveLayout::Char(_) => {
426                // char is 4 bytes
427                4
428            }
429            PrimitiveLayout::Float(float_def) => float_def.size,
430            PrimitiveLayout::Function(_)
431            | PrimitiveLayout::Pointer(_)
432            | PrimitiveLayout::Reference(_) => {
433                // size of a pointer
434                size_of::<usize>()
435            }
436            PrimitiveLayout::Int(int_def) => {
437                // size of an int
438                int_def.size
439            }
440            PrimitiveLayout::Never(_) => {
441                // never type is 0 bytes
442                0
443            }
444            PrimitiveLayout::Slice(_) => size_of::<&[u8]>(),
445            PrimitiveLayout::Str(_) => unimplemented!(),
446            PrimitiveLayout::StrSlice(_) => size_of::<&str>(),
447            PrimitiveLayout::Tuple(tuple_def) => tuple_def.size,
448            PrimitiveLayout::Unit(_) => 0,
449            PrimitiveLayout::UnsignedInt(unsigned_int_def) => {
450                // size of an unsigned int
451                unsigned_int_def.size
452            }
453        };
454
455        Some(size)
456    }
457
458    fn matching_type(&self, other: &Self) -> bool {
459        use PrimitiveLayout::*;
460        match (self, other) {
461            (Pointer(l), Pointer(r)) => l.pointed_type.matching_type(&r.pointed_type),
462            (Reference(l), Reference(r)) => l.pointed_type.matching_type(&r.pointed_type),
463            (Slice(l), Slice(r)) => l.element_type.matching_type(&r.element_type),
464            (Array(l), Array(r)) => l.element_type.matching_type(&r.element_type),
465            (Tuple(l), Tuple(r)) => {
466                if l.elements.len() != r.elements.len() {
467                    return false;
468                }
469                l.elements
470                    .iter()
471                    .zip(r.elements.iter())
472                    .all(|((_, l), (_, r))| l.matching_type(r))
473            }
474
475            (Function(l), Function(r)) => {
476                l.arg_types.len() == r.arg_types.len()
477                    && l.return_type.is_none() == r.return_type.is_none()
478                    && l.return_type
479                        .as_ref()
480                        .zip(r.return_type.as_ref())
481                        .is_none_or(|(l_ret, r_ret)| l_ret.matching_type(r_ret))
482                    && l.arg_types
483                        .iter()
484                        .zip(r.arg_types.iter())
485                        .all(|(l_arg, r_arg)| l_arg.matching_type(r_arg))
486            }
487            (Bool(_), Bool(_))
488            | (Char(_), Char(_))
489            | (Never(_), Never(_))
490            | (Str(_), Str(_))
491            | (Unit(_), Unit(_)) => true,
492            (Float(l), Float(r)) => l == r,
493            (Int(l), Int(r)) => l == r,
494            (UnsignedInt(l), UnsignedInt(r)) => l == r,
495
496            (StrSlice(l), StrSlice(r)) => l == r,
497            _ => false,
498        }
499    }
500}
501
502#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
503pub struct ArrayLayout<L = ()>
504where
505    L: Location,
506{
507    pub element_type: TypeDefinition<L>,
508    pub length: usize,
509}
510
511#[derive(Debug, PartialEq, Eq, Clone, Hash, Update, Copy)]
512pub struct FloatLayout {
513    pub size: usize,
514}
515#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
516pub struct FunctionLayout<L = ()>
517where
518    L: Location,
519{
520    pub return_type: Option<TypeDefinition<L>>,
521    pub arg_types: Vec<TypeDefinition<L>>,
522}
523
524impl<L: Location> FunctionLayout<L> {
525    pub fn display_name(&self) -> String {
526        let arg_types = self
527            .arg_types
528            .iter()
529            .map(|arg| arg.display_name())
530            .collect::<Vec<_>>()
531            .join(", ");
532
533        let mut signature = format!("fn({arg_types})");
534
535        if let Some(l) = self.return_type.as_ref() {
536            signature += &format!(" -> {}", l.display_name());
537        }
538        signature
539    }
540}
541
542#[derive(Debug, PartialEq, Eq, Clone, Hash, Update, Copy)]
543pub struct IntLayout {
544    pub size: usize,
545}
546
547impl IntLayout {
548    pub fn display_name(&self) -> String {
549        format!("i{}", self.size * 8)
550    }
551}
552
553#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
554pub struct PointerLayout<L = ()>
555where
556    L: Location,
557{
558    pub mutable: bool,
559    pub pointed_type: TypeDefinition<L>,
560}
561#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
562pub struct ReferenceLayout<L = ()>
563where
564    L: Location,
565{
566    /// Is this a mutable reference?
567    /// (i.e. `&mut T` vs `&T`)
568    pub mutable: bool,
569
570    pub pointed_type: TypeDefinition<L>,
571}
572
573#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
574pub struct SliceLayout<L = ()>
575where
576    L: Location,
577{
578    pub element_type: TypeDefinition<L>,
579    pub data_ptr_offset: usize,
580    pub length_offset: usize,
581}
582
583#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
584pub struct StrSliceLayout {
585    pub data_ptr_offset: usize,
586    pub length_offset: usize,
587}
588
589#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
590pub struct TupleLayout<L = ()>
591where
592    L: Location,
593{
594    /// List of elements + offsets to their data
595    pub elements: Vec<(usize, TypeDefinition<L>)>,
596    pub size: usize,
597}
598#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
599pub struct UnitLayout;
600
601#[derive(Debug, PartialEq, Eq, Clone, Hash, Update, Copy)]
602pub struct UnsignedIntLayout {
603    /// Size in bytes
604    /// (e.g. 1 for u8, 2 for u16, etc.)
605    pub size: usize,
606}
607
608impl UnsignedIntLayout {
609    pub fn display_name(&self) -> String {
610        format!("u{}", self.size * 8)
611    }
612}
613
614#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
615pub enum StdLayout<L = ()>
616where
617    L: Location,
618{
619    SmartPtr(SmartPtrLayout<L>),
620    Map(MapLayout<L>),
621    Option(OptionLayout<L>),
622    Result(ResultLayout<L>),
623    String(StringLayout<L>),
624    Vec(VecLayout<L>),
625}
626
627impl<L: Location> StdLayout<L> {
628    fn size(&self) -> Option<usize> {
629        let size = match self {
630            StdLayout::SmartPtr(smart_ptr_def) => match smart_ptr_def.variant {
631                SmartPtrVariant::Box => size_of::<Box<()>>(),
632                SmartPtrVariant::Rc => size_of::<std::rc::Rc<()>>(),
633                SmartPtrVariant::Arc => size_of::<std::sync::Arc<()>>(),
634                SmartPtrVariant::RefCell => size_of::<std::cell::RefCell<()>>(),
635                SmartPtrVariant::Mutex => size_of::<std::sync::Mutex<()>>(),
636                SmartPtrVariant::RwLock => size_of::<std::sync::RwLock<()>>(),
637                SmartPtrVariant::Cell => size_of::<std::cell::Cell<()>>(),
638                SmartPtrVariant::UnsafeCell => size_of::<std::cell::UnsafeCell<()>>(),
639            },
640            StdLayout::Map(map_def) => match map_def.variant {
641                MapVariant::HashMap { .. } => size_of::<std::collections::HashMap<(), ()>>(),
642                MapVariant::BTreeMap { .. } => size_of::<std::collections::BTreeMap<(), ()>>(),
643                MapVariant::IndexMap => unimplemented!(),
644            },
645            StdLayout::Option(def) => def.size,
646            StdLayout::Result(def) => def.size,
647            StdLayout::String(_) | StdLayout::Vec(_) => size_of::<Vec<()>>(),
648        };
649
650        Some(size)
651    }
652
653    fn matching_type(&self, other: &Self) -> bool {
654        match (self, other) {
655            (StdLayout::SmartPtr(l), StdLayout::SmartPtr(r)) => {
656                l.variant == r.variant && l.inner_type.matching_type(&r.inner_type)
657            }
658            (StdLayout::Map(l), StdLayout::Map(r)) => {
659                l.variant == r.variant
660                    && l.key_type.matching_type(&r.key_type)
661                    && l.value_type.matching_type(&r.value_type)
662            }
663            (StdLayout::Option(l), StdLayout::Option(r)) => l.some_type.matching_type(&r.some_type),
664            (StdLayout::Result(l), StdLayout::Result(r)) => {
665                l.ok_type.matching_type(&r.ok_type) && l.err_type.matching_type(&r.err_type)
666            }
667            (StdLayout::String(_), StdLayout::String(_)) => true,
668            (StdLayout::Vec(l), StdLayout::Vec(r)) => l.inner_type.matching_type(&r.inner_type),
669            _ => false,
670        }
671    }
672}
673
674#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
675pub struct SmartPtrLayout<L = ()>
676where
677    L: Location,
678{
679    pub inner_type: TypeDefinition<L>,
680    pub inner_ptr_offset: usize,
681    pub data_ptr_offset: usize,
682    pub variant: SmartPtrVariant,
683}
684
685#[derive(Debug, PartialEq, Eq, Clone, Hash, Update, Copy)]
686pub enum SmartPtrVariant {
687    Box,
688    Rc,
689    Arc,
690    RefCell,
691    Mutex,
692    RwLock,
693    Cell,
694    UnsafeCell,
695}
696
697impl SmartPtrVariant {
698    pub fn name(&self) -> &'static str {
699        match self {
700            SmartPtrVariant::Box => "Box",
701            SmartPtrVariant::Rc => "Rc",
702            SmartPtrVariant::Arc => "Arc",
703            SmartPtrVariant::RefCell => "RefCell",
704            SmartPtrVariant::Mutex => "Mutex",
705            SmartPtrVariant::RwLock => "RwLock",
706            SmartPtrVariant::Cell => "Cell",
707            SmartPtrVariant::UnsafeCell => "UnsafeCell",
708        }
709    }
710}
711
712#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
713pub struct MapLayout<L = ()>
714where
715    L: Location,
716{
717    pub key_type: TypeDefinition<L>,
718    pub value_type: TypeDefinition<L>,
719    pub variant: MapVariant,
720}
721
722impl<L: Location> MapLayout<L> {
723    pub fn display_name(&self) -> String {
724        format!(
725            "{}<{}, {}>",
726            self.variant.name(),
727            self.key_type.display_name(),
728            self.value_type.display_name()
729        )
730    }
731}
732
733#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
734pub struct BTreeRootLayout {
735    pub node_offset: usize,   // offset to node field within Root
736    pub height_offset: usize, // offset to height field within Root
737}
738
739#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
740pub struct BTreeNodeLayout {
741    pub keys_offset: usize,  // offset to keys array in LeafNode
742    pub vals_offset: usize,  // offset to vals array in LeafNode
743    pub len_offset: usize,   // offset to len field in LeafNode
744    pub edges_offset: usize, // offset to edges array in InternalNode
745}
746
747#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
748pub enum MapVariant {
749    HashMap {
750        bucket_mask_offset: usize, // offset within RawTableInner
751        ctrl_offset: usize,        // offset to ctrl pointer
752        items_offset: usize,       // offset to items count
753        pair_size: usize,          // size of a single key-value pair
754        key_offset: usize,         // offset to key within a pair
755        value_offset: usize,       // offset to value within a pair
756    },
757    BTreeMap {
758        length_offset: usize,         // offset to length field in BTreeMap
759        root_offset: usize,           // offset to root field in BTreeMap
760        root_layout: BTreeRootLayout, // layout of the root structure
761        node_layout: BTreeNodeLayout, // layout of the node structures
762    },
763    IndexMap,
764}
765
766impl MapVariant {
767    pub fn name(&self) -> &'static str {
768        match self {
769            MapVariant::HashMap { .. } => "HashMap",
770            MapVariant::BTreeMap { .. } => "BTreeMap",
771            MapVariant::IndexMap => "IndexMap",
772        }
773    }
774}
775
776#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
777pub struct StringLayout<L = ()>(pub VecLayout<L>)
778where
779    L: Location;
780
781#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
782pub struct VecLayout<L = ()>
783where
784    L: Location,
785{
786    /// Offset to the length field (vec.len)
787    pub length_offset: usize,
788    /// Offset to the data pointer (vec.buf.inner.ptr.pointer)
789    pub data_ptr_offset: usize,
790    /// Offset to the capacity value (vec.buf.inner.cap.__0)
791    pub capacity_offset: usize,
792    /// The element type of the Vec
793    pub inner_type: TypeDefinition<L>,
794}
795
796impl<L: Location + Default> VecLayout<L> {
797    pub fn new<T: Into<Layout<L>>>(inner_type: T) -> Self {
798        Self {
799            length_offset: 0,
800            data_ptr_offset: 0,
801            capacity_offset: 0,
802            inner_type: TypeDefinition::new(Default::default(), inner_type.into()),
803        }
804    }
805}
806
807#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
808pub struct StructLayout<L = ()>
809where
810    L: Location,
811{
812    pub name: String,
813    pub size: usize,
814    pub alignment: usize,
815    pub fields: Vec<StructField<L>>,
816}
817#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
818pub struct StructField<L = ()>
819where
820    L: Location,
821{
822    pub name: String,
823    pub offset: usize,
824    pub ty: TypeDefinition<L>,
825}
826
827#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
828pub struct Discriminant {
829    pub ty: DiscriminantType,
830    pub offset: usize,
831}
832
833impl Discriminant {
834    pub fn size(&self) -> usize {
835        match &self.ty {
836            DiscriminantType::Int(int_def) => int_def.size,
837            DiscriminantType::UnsignedInt(unsigned_int_def) => unsigned_int_def.size,
838            DiscriminantType::Implicit => 4, // no idea?
839        }
840    }
841}
842
843#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
844pub enum DiscriminantType {
845    Int(IntLayout),
846    UnsignedInt(UnsignedIntLayout),
847    Implicit,
848}
849
850#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
851pub struct EnumLayout<L = ()>
852where
853    L: Location,
854{
855    pub name: String,
856    pub discriminant: Discriminant,
857    pub variants: Vec<EnumVariantLayout<L>>,
858    pub size: usize,
859}
860
861#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
862pub struct EnumVariantLayout<L = ()>
863where
864    L: Location,
865{
866    pub name: String,
867    /// The discriminant value for this variant, if known
868    ///
869    /// If `None`, we should use the index of the variant
870    /// in the `variants` vector as the discriminant value.
871    pub discriminant: Option<i128>,
872    pub layout: TypeDefinition<L>,
873}
874
875#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
876pub struct OptionLayout<L = ()>
877where
878    L: Location,
879{
880    pub name: String,
881    pub discriminant: Discriminant,
882    pub some_offset: usize,
883    pub some_type: TypeDefinition<L>,
884    pub size: usize,
885}
886
887#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
888pub struct ResultLayout<L = ()>
889where
890    L: Location,
891{
892    pub name: String,
893    pub discriminant: Discriminant,
894    pub ok_type: TypeDefinition<L>,
895    pub ok_offset: usize,
896    pub err_type: TypeDefinition<L>,
897    pub err_offset: usize,
898    pub size: usize,
899}
900
901#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
902pub struct CEnumLayout {
903    pub name: String,
904    pub discriminant_type: DiscriminantType,
905    pub variants: Vec<CEnumVariant>,
906    pub size: usize,
907}
908
909#[derive(Debug, PartialEq, Eq, Clone, Hash, Update)]
910pub struct CEnumVariant {
911    pub name: String,
912    pub value: i128,
913}
914
915// Helper functions for common patterns
916impl UnsignedIntLayout {
917    pub fn u8() -> Self {
918        Self { size: 1 }
919    }
920    pub fn u32() -> Self {
921        Self { size: 4 }
922    }
923    pub fn u64() -> Self {
924        Self { size: 8 }
925    }
926}
927
928impl IntLayout {
929    pub fn i32() -> Self {
930        Self { size: 4 }
931    }
932}
933
934impl<L: Location + Default> ReferenceLayout<L> {
935    pub fn new_mutable<T: Into<Layout<L>>>(pointed_type: T) -> Self {
936        Self {
937            mutable: true,
938            pointed_type: TypeDefinition::new(Default::default(), pointed_type.into()),
939        }
940    }
941
942    pub fn new_immutable<T: Into<Layout<L>>>(pointed_type: T) -> Self {
943        Self {
944            mutable: false,
945            pointed_type: TypeDefinition::new(Default::default(), pointed_type.into()),
946        }
947    }
948}