aldrin_core/
introspection.rs1mod array_type;
2mod built_in_type;
3mod enum_fallback;
4mod enum_ty;
5mod event;
6mod event_fallback;
7mod field;
8mod function;
9mod function_fallback;
10mod layout;
11mod lexical_id;
12mod map_type;
13mod newtype;
14mod result_type;
15mod service;
16mod struct_fallback;
17mod struct_ty;
18#[cfg(test)]
19mod test;
20mod type_id;
21mod variant;
22
23pub mod ir;
24#[doc(hidden)]
25pub mod private;
26
27use crate::tags::{self, PrimaryTag, Tag};
28use crate::{
29 Deserialize, DeserializeError, Deserializer, Serialize, SerializeError, Serializer, TypeId,
30};
31use num_enum::{IntoPrimitive, TryFromPrimitive};
32use std::collections::{BTreeMap, HashSet};
33
34pub use array_type::ArrayType;
35pub use built_in_type::BuiltInType;
36pub use enum_fallback::EnumFallback;
37pub use enum_ty::Enum;
38pub use event::Event;
39pub use event_fallback::EventFallback;
40pub use field::Field;
41pub use function::Function;
42pub use function_fallback::FunctionFallback;
43pub use layout::Layout;
44pub use lexical_id::LexicalId;
45pub use map_type::MapType;
46pub use newtype::Newtype;
47pub use result_type::ResultType;
48pub use service::Service;
49pub use struct_fallback::StructFallback;
50pub use struct_ty::Struct;
51pub use variant::Variant;
52
53pub const VERSION: u32 = 2;
54
55#[derive(Debug, Clone, PartialEq, Eq)]
56#[cfg_attr(
57 feature = "serde",
58 derive(serde::Serialize, serde::Deserialize),
59 serde(rename_all = "kebab-case")
60)]
61pub struct Introspection {
62 type_id: TypeId,
63 layout: Layout,
64
65 #[cfg_attr(
66 feature = "serde",
67 serde(default, skip_serializing_if = "HashSet::is_empty")
68 )]
69 references: HashSet<TypeId>,
70}
71
72impl Introspection {
73 pub fn new<T: Introspectable + ?Sized>() -> Self {
74 Self::from_dyn(DynIntrospectable::new::<T>())
75 }
76
77 pub fn from_dyn(ty: DynIntrospectable) -> Self {
78 let introspection = ir::IntrospectionIr::from_dyn(ty);
79 Self::from_ir(introspection)
80 }
81
82 pub fn from_ir(introspection: ir::IntrospectionIr) -> Self {
83 let layout = Layout::from_ir(introspection.layout, &introspection.references);
84 let references = introspection.references.into_values().collect();
85
86 Self {
87 type_id: introspection.type_id,
88 layout,
89 references,
90 }
91 }
92
93 pub fn type_id(&self) -> TypeId {
94 self.type_id
95 }
96
97 pub fn layout(&self) -> &Layout {
98 &self.layout
99 }
100
101 pub fn references(&self) -> &HashSet<TypeId> {
102 &self.references
103 }
104
105 pub fn iter_references(&self) -> impl ExactSizeIterator<Item = TypeId> + '_ {
106 self.references.iter().copied()
107 }
108
109 pub fn as_built_in_layout(&self) -> Option<BuiltInType> {
110 self.layout.as_built_in()
111 }
112
113 pub fn as_struct_layout(&self) -> Option<&Struct> {
114 self.layout.as_struct()
115 }
116
117 pub fn as_enum_layout(&self) -> Option<&Enum> {
118 self.layout.as_enum()
119 }
120
121 pub fn as_service_layout(&self) -> Option<&Service> {
122 self.layout.as_service()
123 }
124
125 pub fn as_newtype_layout(&self) -> Option<&Newtype> {
126 self.layout.as_newtype()
127 }
128}
129
130impl From<ir::IntrospectionIr> for Introspection {
131 fn from(introspection: ir::IntrospectionIr) -> Self {
132 Self::from_ir(introspection)
133 }
134}
135
136#[derive(IntoPrimitive, TryFromPrimitive)]
137#[repr(u32)]
138enum IntrospectionField {
139 Version = 0,
140 TypeId = 1,
141 Layout = 2,
142 References = 3,
143}
144
145impl Tag for Introspection {}
146
147impl PrimaryTag for Introspection {
148 type Tag = Self;
149}
150
151impl Serialize<Self> for Introspection {
152 fn serialize(self, serializer: Serializer) -> Result<(), SerializeError> {
153 serializer.serialize(&self)
154 }
155}
156
157impl Serialize<Introspection> for &Introspection {
158 fn serialize(self, serializer: Serializer) -> Result<(), SerializeError> {
159 let mut serializer = serializer.serialize_struct1(4)?;
160
161 serializer.serialize::<tags::U32>(IntrospectionField::Version, VERSION)?;
162 serializer.serialize::<TypeId>(IntrospectionField::TypeId, self.type_id)?;
163 serializer.serialize::<Layout>(IntrospectionField::Layout, &self.layout)?;
164
165 serializer
166 .serialize::<tags::Set<TypeId>>(IntrospectionField::References, &self.references)?;
167
168 serializer.finish()
169 }
170}
171
172impl Deserialize<Self> for Introspection {
173 fn deserialize(deserializer: Deserializer) -> Result<Self, DeserializeError> {
174 let mut deserializer = deserializer.deserialize_struct()?;
175
176 let mut type_id = None;
177 let mut layout = None;
178 let mut references = None;
179
180 while let Some(deserializer) = deserializer.deserialize()? {
181 match deserializer.try_id() {
182 Ok(IntrospectionField::Version) => {
183 if deserializer.deserialize::<tags::U32, u32>()? != VERSION {
184 return Err(DeserializeError::InvalidSerialization);
185 }
186 }
187
188 Ok(IntrospectionField::TypeId) => {
189 type_id = deserializer.deserialize::<TypeId, _>().map(Some)?;
190 }
191
192 Ok(IntrospectionField::Layout) => {
193 layout = deserializer.deserialize::<Layout, _>().map(Some)?;
194 }
195
196 Ok(IntrospectionField::References) => {
197 references = deserializer
198 .deserialize::<tags::Set<TypeId>, _>()
199 .map(Some)?;
200 }
201
202 Err(_) => deserializer.skip()?,
203 }
204 }
205
206 deserializer.finish(Self {
207 type_id: type_id.ok_or(DeserializeError::InvalidSerialization)?,
208 layout: layout.ok_or(DeserializeError::InvalidSerialization)?,
209 references: references.ok_or(DeserializeError::InvalidSerialization)?,
210 })
211 }
212}
213
214#[derive(Debug)]
215pub struct References<'a> {
216 inner: &'a mut Vec<DynIntrospectable>,
217}
218
219impl<'a> References<'a> {
220 pub fn new(inner: &'a mut Vec<DynIntrospectable>) -> Self {
221 Self { inner }
222 }
223
224 pub fn add<T: Introspectable + ?Sized>(&mut self) {
225 self.add_dyn(DynIntrospectable::new::<T>());
226 }
227
228 pub fn add_dyn(&mut self, ty: DynIntrospectable) {
229 self.inner.push(ty);
230 }
231
232 pub fn reserve(&mut self, additional: usize) {
233 self.inner.reserve(additional);
234 }
235}
236
237impl Extend<DynIntrospectable> for References<'_> {
238 fn extend<T>(&mut self, iter: T)
239 where
240 T: IntoIterator<Item = DynIntrospectable>,
241 {
242 self.inner.extend(iter);
243 }
244}
245
246pub trait Introspectable {
247 fn layout() -> ir::LayoutIr;
248 fn lexical_id() -> LexicalId;
249 fn add_references(references: &mut References);
250}
251
252#[derive(Debug, Copy, Clone)]
253pub struct DynIntrospectable {
254 layout: fn() -> ir::LayoutIr,
255 lexical_id: fn() -> LexicalId,
256 add_references: fn(&mut References),
257}
258
259impl DynIntrospectable {
260 pub fn new<T: Introspectable + ?Sized>() -> Self {
261 Self {
262 layout: T::layout,
263 lexical_id: T::lexical_id,
264 add_references: T::add_references,
265 }
266 }
267
268 pub fn layout(self) -> ir::LayoutIr {
269 (self.layout)()
270 }
271
272 pub fn lexical_id(self) -> LexicalId {
273 (self.lexical_id)()
274 }
275
276 pub fn add_references(self, references: &mut References) {
277 (self.add_references)(references)
278 }
279}
280
281#[track_caller]
282fn resolve_ir(lexical_id: LexicalId, references: &BTreeMap<LexicalId, TypeId>) -> TypeId {
283 references
284 .get(&lexical_id)
285 .copied()
286 .expect("incomplete introspection references")
287}