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}