aldrin_core/introspection/
struct_ty.rs1use super::{Field, LexicalId};
2use crate::error::{DeserializeError, SerializeError};
3use crate::value_deserializer::{Deserialize, Deserializer};
4use crate::value_serializer::{Serialize, Serializer};
5use num_enum::{IntoPrimitive, TryFromPrimitive};
6use std::collections::BTreeMap;
7use uuid::{uuid, Uuid};
8
9#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
10pub struct Struct {
11    schema: String,
12    name: String,
13    fields: BTreeMap<u32, Field>,
14    fallback: Option<String>,
15}
16
17impl Struct {
18    pub const NAMESPACE: Uuid = uuid!("83742d78-4e60-44b2-84e7-75904c5987c1");
19
20    pub fn builder(schema: impl Into<String>, name: impl Into<String>) -> StructBuilder {
21        StructBuilder::new(schema, name)
22    }
23
24    pub fn lexical_id(&self) -> LexicalId {
25        LexicalId::custom(&self.schema, &self.name)
26    }
27
28    pub fn schema(&self) -> &str {
29        &self.schema
30    }
31
32    pub fn name(&self) -> &str {
33        &self.name
34    }
35
36    pub fn fields(&self) -> &BTreeMap<u32, Field> {
37        &self.fields
38    }
39
40    pub fn fallback(&self) -> Option<&str> {
41        self.fallback.as_deref()
42    }
43}
44
45#[derive(IntoPrimitive, TryFromPrimitive)]
46#[repr(u32)]
47enum StructField {
48    Schema = 0,
49    Name = 1,
50    Fields = 2,
51    Fallback = 3,
52}
53
54impl Serialize for Struct {
55    fn serialize(&self, serializer: Serializer) -> Result<(), SerializeError> {
56        let num = 3 + (self.fallback.is_some() as usize);
57        let mut serializer = serializer.serialize_struct(num)?;
58
59        serializer.serialize_field(StructField::Schema, &self.schema)?;
60        serializer.serialize_field(StructField::Name, &self.name)?;
61        serializer.serialize_field(StructField::Fields, &self.fields)?;
62
63        if self.fallback.is_some() {
64            serializer.serialize_field(StructField::Fallback, &self.fallback)?;
65        }
66
67        serializer.finish()
68    }
69}
70
71impl Deserialize for Struct {
72    fn deserialize(deserializer: Deserializer) -> Result<Self, DeserializeError> {
73        let mut deserializer = deserializer.deserialize_struct()?;
74
75        let mut schema = None;
76        let mut name = None;
77        let mut fields = None;
78        let mut fallback = None;
79
80        while deserializer.has_more_fields() {
81            let deserializer = deserializer.deserialize_field()?;
82
83            match deserializer.try_id()? {
84                StructField::Schema => schema = deserializer.deserialize().map(Some)?,
85                StructField::Name => name = deserializer.deserialize().map(Some)?,
86                StructField::Fields => fields = deserializer.deserialize().map(Some)?,
87                StructField::Fallback => fallback = deserializer.deserialize()?,
88            }
89        }
90
91        deserializer.finish(Self {
92            schema: schema.ok_or(DeserializeError::InvalidSerialization)?,
93            name: name.ok_or(DeserializeError::InvalidSerialization)?,
94            fields: fields.ok_or(DeserializeError::InvalidSerialization)?,
95            fallback,
96        })
97    }
98}
99
100#[derive(Debug, Clone)]
101pub struct StructBuilder {
102    schema: String,
103    name: String,
104    fields: BTreeMap<u32, Field>,
105    fallback: Option<String>,
106}
107
108impl StructBuilder {
109    pub fn new(schema: impl Into<String>, name: impl Into<String>) -> Self {
110        Self {
111            schema: schema.into(),
112            name: name.into(),
113            fields: BTreeMap::new(),
114            fallback: None,
115        }
116    }
117
118    pub fn field(
119        mut self,
120        id: u32,
121        name: impl Into<String>,
122        is_required: bool,
123        field_type: LexicalId,
124    ) -> Self {
125        self.fields
126            .insert(id, Field::new(id, name, is_required, field_type));
127        self
128    }
129
130    pub fn fallback(mut self, name: impl Into<String>) -> Self {
131        self.fallback = Some(name.into());
132        self
133    }
134
135    pub fn finish(self) -> Struct {
136        Struct {
137            schema: self.schema,
138            name: self.name,
139            fields: self.fields,
140            fallback: self.fallback,
141        }
142    }
143}