aldrin_core/introspection/
struct_ty.rs

1use super::{ir, Field, LexicalId, StructFallback};
2use crate::tags::{self, PrimaryTag, Tag};
3use crate::{
4    Deserialize, DeserializeError, Deserializer, Serialize, SerializeError, Serializer, TypeId,
5};
6use num_enum::{IntoPrimitive, TryFromPrimitive};
7use std::collections::BTreeMap;
8
9#[derive(Debug, Clone, PartialEq, Eq)]
10#[cfg_attr(
11    feature = "serde",
12    derive(serde::Serialize, serde::Deserialize),
13    serde(rename_all = "kebab-case")
14)]
15pub struct Struct {
16    schema: String,
17    name: String,
18
19    #[cfg_attr(
20        feature = "serde",
21        serde(default, skip_serializing_if = "Option::is_none")
22    )]
23    doc: Option<String>,
24
25    #[cfg_attr(
26        feature = "serde",
27        serde(default, skip_serializing_if = "BTreeMap::is_empty")
28    )]
29    fields: BTreeMap<u32, Field>,
30
31    #[cfg_attr(
32        feature = "serde",
33        serde(default, skip_serializing_if = "Option::is_none")
34    )]
35    fallback: Option<StructFallback>,
36}
37
38impl Struct {
39    pub fn from_ir(ty: ir::StructIr, references: &BTreeMap<LexicalId, TypeId>) -> Self {
40        Self {
41            schema: ty.schema,
42            name: ty.name,
43            doc: ty.doc,
44            fields: ty
45                .fields
46                .into_iter()
47                .map(|(id, field)| (id, Field::from_ir(field, references)))
48                .collect(),
49            fallback: ty.fallback.map(StructFallback::from_ir),
50        }
51    }
52
53    pub fn schema(&self) -> &str {
54        &self.schema
55    }
56
57    pub fn name(&self) -> &str {
58        &self.name
59    }
60
61    pub fn doc(&self) -> Option<&str> {
62        self.doc.as_deref()
63    }
64
65    pub fn fields(&self) -> &BTreeMap<u32, Field> {
66        &self.fields
67    }
68
69    pub fn fallback(&self) -> Option<&StructFallback> {
70        self.fallback.as_ref()
71    }
72}
73
74#[derive(IntoPrimitive, TryFromPrimitive)]
75#[repr(u32)]
76enum StructField {
77    Schema = 0,
78    Name = 1,
79    Doc = 2,
80    Fields = 3,
81    Fallback = 4,
82}
83
84impl Tag for Struct {}
85
86impl PrimaryTag for Struct {
87    type Tag = Self;
88}
89
90impl Serialize<Self> for Struct {
91    fn serialize(self, serializer: Serializer) -> Result<(), SerializeError> {
92        serializer.serialize(&self)
93    }
94}
95
96impl Serialize<Struct> for &Struct {
97    fn serialize(self, serializer: Serializer) -> Result<(), SerializeError> {
98        let mut serializer = serializer.serialize_struct2()?;
99
100        serializer.serialize::<tags::String>(StructField::Schema, &self.schema)?;
101        serializer.serialize::<tags::String>(StructField::Name, &self.name)?;
102        serializer.serialize_if_some::<tags::Option<tags::String>>(StructField::Doc, &self.doc)?;
103        serializer.serialize::<tags::Map<tags::U32, Field>>(StructField::Fields, &self.fields)?;
104
105        serializer.serialize_if_some::<tags::Option<StructFallback>>(
106            StructField::Fallback,
107            &self.fallback,
108        )?;
109
110        serializer.finish()
111    }
112}
113
114impl Deserialize<Self> for Struct {
115    fn deserialize(deserializer: Deserializer) -> Result<Self, DeserializeError> {
116        let mut deserializer = deserializer.deserialize_struct()?;
117
118        let mut schema = None;
119        let mut name = None;
120        let mut doc = None;
121        let mut fields = None;
122        let mut fallback = None;
123
124        while let Some(deserializer) = deserializer.deserialize()? {
125            match deserializer.try_id() {
126                Ok(StructField::Schema) => {
127                    schema = deserializer.deserialize::<tags::String, _>().map(Some)?;
128                }
129
130                Ok(StructField::Name) => {
131                    name = deserializer.deserialize::<tags::String, _>().map(Some)?;
132                }
133
134                Ok(StructField::Doc) => {
135                    doc = deserializer.deserialize::<tags::Option<tags::String>, _>()?;
136                }
137
138                Ok(StructField::Fields) => {
139                    fields = deserializer
140                        .deserialize::<tags::Map<tags::U32, Field>, _>()
141                        .map(Some)?;
142                }
143
144                Ok(StructField::Fallback) => {
145                    fallback = deserializer.deserialize::<tags::Option<StructFallback>, _>()?;
146                }
147
148                Err(_) => deserializer.skip()?,
149            }
150        }
151
152        deserializer.finish(Self {
153            schema: schema.ok_or(DeserializeError::InvalidSerialization)?,
154            name: name.ok_or(DeserializeError::InvalidSerialization)?,
155            doc,
156            fields: fields.ok_or(DeserializeError::InvalidSerialization)?,
157            fallback,
158        })
159    }
160}