aldrin_core/
introspection.rs1mod array_type;
2mod built_in_type;
3mod enum_ty;
4mod event;
5mod field;
6mod function;
7mod key_type;
8mod layout;
9mod lexical_id;
10mod map_type;
11mod result_type;
12mod service;
13mod struct_ty;
14#[cfg(test)]
15mod test;
16mod type_id;
17mod variant;
18
19#[doc(hidden)]
20pub mod private;
21
22use crate::error::{DeserializeError, SerializeError};
23use crate::ids::TypeId;
24use crate::value_deserializer::{Deserialize, Deserializer};
25use crate::value_serializer::{Serialize, Serializer};
26use num_enum::{IntoPrimitive, TryFromPrimitive};
27use std::collections::BTreeMap;
28
29pub use array_type::ArrayType;
30pub use built_in_type::BuiltInType;
31pub use enum_ty::{Enum, EnumBuilder};
32pub use event::Event;
33pub use field::Field;
34pub use function::Function;
35pub use key_type::{KeyType, KeyTypeOf};
36pub use layout::Layout;
37pub use lexical_id::LexicalId;
38pub use map_type::MapType;
39pub use result_type::ResultType;
40pub use service::{Service, ServiceBuilder};
41pub use struct_ty::{Struct, StructBuilder};
42pub use variant::Variant;
43
44pub const VERSION: u32 = 1;
45
46#[derive(Debug, Clone)]
47pub struct Introspection {
48    type_id: TypeId,
49    layout: Layout,
50    references: BTreeMap<LexicalId, TypeId>,
51}
52
53impl Introspection {
54    pub fn new<T: Introspectable + ?Sized>() -> Self {
55        Self::from_dyn(DynIntrospectable::new::<T>())
56    }
57
58    pub fn from_dyn(ty: DynIntrospectable) -> Self {
59        let mut types = Vec::new();
60        ty.add_references(&mut References::new(&mut types));
61
62        let mut references = BTreeMap::new();
63        for ty in types {
64            let type_id = TypeId::compute_from_dyn(ty);
65            let dup = references.insert(ty.lexical_id(), type_id);
66            assert!(dup.is_none() || (dup == Some(type_id)));
67        }
68
69        Self {
70            type_id: TypeId::compute_from_dyn(ty),
71            layout: ty.layout(),
72            references,
73        }
74    }
75
76    pub fn lexical_id(&self) -> LexicalId {
77        self.layout.lexical_id()
78    }
79
80    pub fn type_id(&self) -> TypeId {
81        self.type_id
82    }
83
84    pub fn layout(&self) -> &Layout {
85        &self.layout
86    }
87
88    pub fn references(&self) -> &BTreeMap<LexicalId, TypeId> {
89        &self.references
90    }
91
92    pub fn resolve(&self, lexical_id: LexicalId) -> Option<TypeId> {
93        self.references.get(&lexical_id).copied()
94    }
95
96    pub fn iter_references(&self) -> impl ExactSizeIterator<Item = (LexicalId, TypeId)> + '_ {
97        self.references.iter().map(|(k, v)| (*k, *v))
98    }
99
100    pub fn as_built_in_layout(&self) -> Option<BuiltInType> {
101        self.layout.as_built_in()
102    }
103
104    pub fn as_struct_layout(&self) -> Option<&Struct> {
105        self.layout.as_struct()
106    }
107
108    pub fn as_enum_layout(&self) -> Option<&Enum> {
109        self.layout.as_enum()
110    }
111
112    pub fn as_service_layout(&self) -> Option<&Service> {
113        self.layout.as_service()
114    }
115}
116
117#[derive(IntoPrimitive, TryFromPrimitive)]
118#[repr(u32)]
119enum IntrospectionField {
120    Version = 0,
121    TypeId = 1,
122    Layout = 2,
123    References = 3,
124}
125
126impl Serialize for Introspection {
127    fn serialize(&self, serializer: Serializer) -> Result<(), SerializeError> {
128        let mut serializer = serializer.serialize_struct(4)?;
129
130        serializer.serialize_field(IntrospectionField::Version, &VERSION)?;
131        serializer.serialize_field(IntrospectionField::TypeId, &self.type_id)?;
132        serializer.serialize_field(IntrospectionField::Layout, &self.layout)?;
133        serializer.serialize_field(IntrospectionField::References, &self.references)?;
134
135        serializer.finish()
136    }
137}
138
139impl Deserialize for Introspection {
140    fn deserialize(deserializer: Deserializer) -> Result<Self, DeserializeError> {
141        let mut deserializer = deserializer.deserialize_struct()?;
142
143        let version: u32 = deserializer.deserialize_specific_field(IntrospectionField::Version)?;
144        if version != VERSION {
145            return Err(DeserializeError::InvalidSerialization);
146        }
147
148        let type_id = deserializer.deserialize_specific_field(IntrospectionField::TypeId)?;
149        let layout = deserializer.deserialize_specific_field(IntrospectionField::Layout)?;
150        let references = deserializer.deserialize_specific_field(IntrospectionField::References)?;
151
152        deserializer.finish(Self {
153            type_id,
154            layout,
155            references,
156        })
157    }
158}
159
160#[derive(Debug)]
161pub struct References<'a> {
162    inner: &'a mut Vec<DynIntrospectable>,
163}
164
165impl<'a> References<'a> {
166    pub fn new(inner: &'a mut Vec<DynIntrospectable>) -> Self {
167        Self { inner }
168    }
169
170    pub fn add<T: Introspectable + ?Sized>(&mut self) {
171        self.add_dyn(DynIntrospectable::new::<T>());
172    }
173
174    pub fn add_dyn(&mut self, ty: DynIntrospectable) {
175        self.inner.push(ty);
176    }
177
178    pub fn reserve(&mut self, additional: usize) {
179        self.inner.reserve(additional);
180    }
181}
182
183impl Extend<DynIntrospectable> for References<'_> {
184    fn extend<T>(&mut self, iter: T)
185    where
186        T: IntoIterator<Item = DynIntrospectable>,
187    {
188        self.inner.extend(iter);
189    }
190}
191
192pub trait Introspectable {
193    fn layout() -> Layout;
194    fn lexical_id() -> LexicalId;
195    fn add_references(references: &mut References);
196}
197
198#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
199pub struct DynIntrospectable {
200    layout: fn() -> Layout,
201    lexical_id: fn() -> LexicalId,
202    add_references: fn(&mut References),
203}
204
205impl DynIntrospectable {
206    pub fn new<T: Introspectable + ?Sized>() -> Self {
207        Self {
208            layout: T::layout,
209            lexical_id: T::lexical_id,
210            add_references: T::add_references,
211        }
212    }
213
214    pub fn layout(self) -> Layout {
215        (self.layout)()
216    }
217
218    pub fn lexical_id(self) -> LexicalId {
219        (self.lexical_id)()
220    }
221
222    pub fn add_references(self, references: &mut References) {
223        (self.add_references)(references)
224    }
225}