brdb/schema/
as_brdb.rs

1use indexmap::{IndexMap, IndexSet};
2
3use crate::{
4    errors::BrdbSchemaError,
5    schema::{BrdbInterned, BrdbSchema, BrdbSchemaEnum, BrdbValue, WireVariant},
6};
7
8pub type BrdbArrayIter<'a> = Box<dyn ExactSizeIterator<Item = &'a dyn AsBrdbValue> + 'a>;
9pub type BrdbMapIter<'a> =
10    Box<dyn ExactSizeIterator<Item = (&'a dyn AsBrdbValue, &'a dyn AsBrdbValue)> + 'a>;
11
12/// A helper trait to allow serializing implementing types to msgpack schema format
13pub trait AsBrdbValue {
14    fn as_brdb_bool(&self) -> Result<bool, BrdbSchemaError> {
15        Err(BrdbSchemaError::UnimplementedCast(
16            "bool".to_owned(),
17            std::any::type_name::<Self>(),
18        ))
19    }
20    fn as_brdb_u8(&self) -> Result<u8, BrdbSchemaError> {
21        Err(BrdbSchemaError::UnimplementedCast(
22            "u8".to_owned(),
23            std::any::type_name::<Self>(),
24        ))
25    }
26    fn as_brdb_u16(&self) -> Result<u16, BrdbSchemaError> {
27        Err(BrdbSchemaError::UnimplementedCast(
28            "u16".to_owned(),
29            std::any::type_name::<Self>(),
30        ))
31    }
32    fn as_brdb_u32(&self) -> Result<u32, BrdbSchemaError> {
33        Err(BrdbSchemaError::UnimplementedCast(
34            "u32".to_owned(),
35            std::any::type_name::<Self>(),
36        ))
37    }
38    fn as_brdb_u64(&self) -> Result<u64, BrdbSchemaError> {
39        Err(BrdbSchemaError::UnimplementedCast(
40            "u64".to_owned(),
41            std::any::type_name::<Self>(),
42        ))
43    }
44    fn as_brdb_i8(&self) -> Result<i8, BrdbSchemaError> {
45        Err(BrdbSchemaError::UnimplementedCast(
46            "i8".to_owned(),
47            std::any::type_name::<Self>(),
48        ))
49    }
50    fn as_brdb_i16(&self) -> Result<i16, BrdbSchemaError> {
51        Err(BrdbSchemaError::UnimplementedCast(
52            "i16".to_owned(),
53            std::any::type_name::<Self>(),
54        ))
55    }
56    fn as_brdb_i32(&self) -> Result<i32, BrdbSchemaError> {
57        Err(BrdbSchemaError::UnimplementedCast(
58            "i32".to_owned(),
59            std::any::type_name::<Self>(),
60        ))
61    }
62    fn as_brdb_i64(&self) -> Result<i64, BrdbSchemaError> {
63        Err(BrdbSchemaError::UnimplementedCast(
64            "i64".to_owned(),
65            std::any::type_name::<Self>(),
66        ))
67    }
68    fn as_brdb_f32(&self) -> Result<f32, BrdbSchemaError> {
69        Err(BrdbSchemaError::UnimplementedCast(
70            "f32".to_owned(),
71            std::any::type_name::<Self>(),
72        ))
73    }
74    fn as_brdb_f64(&self) -> Result<f64, BrdbSchemaError> {
75        Err(BrdbSchemaError::UnimplementedCast(
76            "f64".to_owned(),
77            std::any::type_name::<Self>(),
78        ))
79    }
80    fn as_brdb_str(&self) -> Result<&str, BrdbSchemaError> {
81        Err(BrdbSchemaError::UnimplementedCast(
82            "str".to_owned(),
83            std::any::type_name::<Self>(),
84        ))
85    }
86    fn as_brdb_asset(
87        &self,
88        _schema: &BrdbSchema,
89        _ty: &str,
90    ) -> Result<Option<usize>, BrdbSchemaError> {
91        Err(BrdbSchemaError::UnimplementedCast(
92            "asset".to_owned(),
93            std::any::type_name::<Self>(),
94        ))
95    }
96    fn as_brdb_enum(
97        &self,
98        _schema: &BrdbSchema,
99        _def: &BrdbSchemaEnum,
100    ) -> Result<i32, BrdbSchemaError> {
101        Err(BrdbSchemaError::UnimplementedCast(
102            "enum".to_owned(),
103            std::any::type_name::<Self>(),
104        ))
105    }
106
107    fn as_brdb_wire_variant(&self) -> Result<crate::schema::value::WireVariant, BrdbSchemaError> {
108        Err(BrdbSchemaError::UnimplementedCast(
109            "wire variant".to_owned(),
110            std::any::type_name::<Self>(),
111        ))
112    }
113
114    /// Read a specific struct property value from the schema.
115    fn as_brdb_struct_prop_value(
116        &self,
117        _schema: &BrdbSchema,
118        _struct_name: BrdbInterned,
119        _prop_name: BrdbInterned,
120    ) -> Result<&dyn AsBrdbValue, BrdbSchemaError> {
121        Err(BrdbSchemaError::UnimplementedCast(
122            "struct property".to_owned(),
123            std::any::type_name::<Self>(),
124        ))
125    }
126
127    /// Get the the number of entries in a struct property.
128    fn as_brdb_struct_prop_array(
129        &self,
130        _schema: &BrdbSchema,
131        _struct_name: BrdbInterned,
132        _prop_name: BrdbInterned,
133    ) -> Result<BrdbArrayIter, BrdbSchemaError> {
134        Err(BrdbSchemaError::UnimplementedCast(
135            "struct property array".to_owned(),
136            std::any::type_name::<Self>(),
137        ))
138    }
139
140    /// Get the the number of entries in a struct property.
141    fn as_brdb_struct_prop_map(
142        &self,
143        _schema: &BrdbSchema,
144        _struct_name: BrdbInterned,
145        _prop_name: BrdbInterned,
146    ) -> Result<BrdbMapIter, BrdbSchemaError> {
147        Err(BrdbSchemaError::UnimplementedCast(
148            "struct property map".to_owned(),
149            std::any::type_name::<Self>(),
150        ))
151    }
152}
153
154impl AsBrdbValue for () {}
155
156macro_rules! as_brdb_fn {
157    ($fn_name:ident, $ty:ty, $method:ident) => {
158        fn $fn_name(&self) -> Result<$ty, BrdbSchemaError> {
159            if let BrdbValue::$method(v) = self {
160                Ok(*v as $ty)
161            } else {
162                Err(BrdbSchemaError::ExpectedType(
163                    stringify!($ty).to_owned(),
164                    self.get_type().to_string(),
165                ))
166            }
167        }
168    };
169}
170
171/// A default impl for `BrdbValue`.
172impl AsBrdbValue for BrdbValue {
173    as_brdb_fn!(as_brdb_bool, bool, Bool);
174    as_brdb_fn!(as_brdb_u8, u8, U8);
175    as_brdb_fn!(as_brdb_u16, u16, U16);
176    as_brdb_fn!(as_brdb_u32, u32, U32);
177    as_brdb_fn!(as_brdb_u64, u64, U64);
178    as_brdb_fn!(as_brdb_i8, i8, I8);
179    as_brdb_fn!(as_brdb_i16, i16, I16);
180    as_brdb_fn!(as_brdb_i32, i32, I32);
181    as_brdb_fn!(as_brdb_i64, i64, I64);
182    as_brdb_fn!(as_brdb_f32, f32, F32);
183    as_brdb_fn!(as_brdb_f64, f64, F64);
184    fn as_brdb_str(&self) -> Result<&str, BrdbSchemaError> {
185        if let BrdbValue::String(s) = self {
186            Ok(s)
187        } else {
188            Err(BrdbSchemaError::ExpectedType(
189                "str".to_owned(),
190                self.get_type().to_string(),
191            ))
192        }
193    }
194    fn as_brdb_asset(
195        &self,
196        _schema: &BrdbSchema,
197        _ty: &str,
198    ) -> Result<Option<usize>, BrdbSchemaError> {
199        if let BrdbValue::Asset(index) = self {
200            Ok(*index)
201        } else {
202            Err(BrdbSchemaError::ExpectedType(
203                "asset".to_owned(),
204                self.get_type().to_string(),
205            ))
206        }
207    }
208    fn as_brdb_enum(
209        &self,
210        _schema: &BrdbSchema,
211        _def: &BrdbSchemaEnum,
212    ) -> Result<i32, BrdbSchemaError> {
213        if let BrdbValue::Enum(e) = self {
214            Ok(e.value as i32)
215        } else {
216            Err(BrdbSchemaError::ExpectedType(
217                "enum".to_owned(),
218                self.get_type().to_string(),
219            ))
220        }
221    }
222    fn as_brdb_wire_variant(&self) -> Result<WireVariant, BrdbSchemaError> {
223        if let BrdbValue::WireVar(wire) = self {
224            Ok(wire.to_owned())
225        } else {
226            Err(BrdbSchemaError::ExpectedType(
227                "wire variant".to_owned(),
228                self.get_type().to_string(),
229            ))
230        }
231    }
232    fn as_brdb_struct_prop_value(
233        &self,
234        schema: &BrdbSchema,
235        _struct_name: BrdbInterned,
236        prop_name: BrdbInterned,
237    ) -> Result<&dyn AsBrdbValue, BrdbSchemaError> {
238        let BrdbValue::Struct(s) = self else {
239            return Err(BrdbSchemaError::ExpectedType(
240                "struct".to_owned(),
241                self.get_type().to_string(),
242            ));
243        };
244
245        if let Some(prop) = s.properties.get(&prop_name) {
246            Ok(prop)
247        } else {
248            Err(BrdbSchemaError::MissingStructField(
249                schema
250                    .intern
251                    .lookup(s.name)
252                    .unwrap_or_else(|| "unknown struct".to_owned()),
253                schema
254                    .intern
255                    .lookup(prop_name)
256                    .unwrap_or_else(|| "unknown property".to_owned()),
257            ))
258        }
259    }
260    fn as_brdb_struct_prop_array(
261        &self,
262        schema: &BrdbSchema,
263        _struct_name: BrdbInterned,
264        prop_name: BrdbInterned,
265    ) -> Result<BrdbArrayIter, BrdbSchemaError> {
266        let BrdbValue::Struct(s) = self else {
267            return Err(BrdbSchemaError::ExpectedType(
268                "struct".to_owned(),
269                self.get_type().to_string(),
270            ));
271        };
272        match s.properties.get(&prop_name) {
273            Some(BrdbValue::Array(vec)) | Some(BrdbValue::FlatArray(vec)) => Ok(vec.as_brdb_iter()),
274            _ => Err(BrdbSchemaError::MissingStructField(
275                schema
276                    .intern
277                    .lookup(s.name)
278                    .unwrap_or_else(|| "unknown struct".to_owned()),
279                schema
280                    .intern
281                    .lookup(prop_name)
282                    .unwrap_or_else(|| "unknown property".to_owned()),
283            )),
284        }
285    }
286    fn as_brdb_struct_prop_map(
287        &self,
288        schema: &BrdbSchema,
289        _struct_name: BrdbInterned,
290        prop_name: BrdbInterned,
291    ) -> Result<BrdbMapIter, BrdbSchemaError> {
292        let BrdbValue::Struct(s) = self else {
293            return Err(BrdbSchemaError::ExpectedType(
294                "struct".to_owned(),
295                self.get_type().to_string(),
296            ));
297        };
298        if let Some(BrdbValue::Map(map)) = s.properties.get(&prop_name) {
299            Ok(Box::new(map.iter().map(|(k, v)| {
300                (k as &dyn AsBrdbValue, v as &dyn AsBrdbValue)
301            })))
302        } else {
303            Err(BrdbSchemaError::MissingStructField(
304                schema
305                    .intern
306                    .lookup(s.name)
307                    .unwrap_or_else(|| "unknown struct".to_owned()),
308                schema
309                    .intern
310                    .lookup(prop_name)
311                    .unwrap_or_else(|| "unknown property".to_owned()),
312            ))
313        }
314    }
315}
316impl AsBrdbValue for WireVariant {
317    fn as_brdb_wire_variant(&self) -> Result<WireVariant, BrdbSchemaError> {
318        Ok(self.clone())
319    }
320}
321
322macro_rules! as_brdb_int(
323    ($ty:ty, $($rest:ty),*) => {
324        as_brdb_int!($ty);
325        as_brdb_int!($($rest),*);
326    };
327    ($ty:ty) => {
328        impl AsBrdbValue for $ty {
329            fn as_brdb_bool(&self) -> Result<bool, BrdbSchemaError> {
330                Ok(*self != 0)
331            }
332            fn as_brdb_u8(&self) -> Result<u8, BrdbSchemaError> {
333                Ok(*self as u8)
334            }
335            fn as_brdb_u16(&self) -> Result<u16, BrdbSchemaError> {
336                Ok(*self as u16)
337            }
338            fn as_brdb_u32(&self) -> Result<u32, BrdbSchemaError> {
339                Ok(*self as u32)
340            }
341            fn as_brdb_u64(&self) -> Result<u64, BrdbSchemaError> {
342                Ok(*self as u64)
343            }
344            fn as_brdb_i8(&self) -> Result<i8, BrdbSchemaError> {
345                Ok(*self as i8)
346            }
347            fn as_brdb_i16(&self) -> Result<i16, BrdbSchemaError> {
348                Ok(*self as i16)
349            }
350            fn as_brdb_i32(&self) -> Result<i32, BrdbSchemaError> {
351                Ok(*self as i32)
352            }
353            fn as_brdb_i64(&self) -> Result<i64, BrdbSchemaError> {
354                Ok(*self as i64)
355            }
356            fn as_brdb_f32(&self) -> Result<f32, BrdbSchemaError> {
357                Ok(*self as f32)
358            }
359            fn as_brdb_f64(&self) -> Result<f64, BrdbSchemaError> {
360                Ok(*self as f64)
361            }
362            fn as_brdb_wire_variant(
363                &self,
364            ) -> Result<WireVariant, BrdbSchemaError> {
365                Ok((*self).into())
366            }
367        }
368    }
369);
370as_brdb_int!(u8, u16, u32, u64, i8, i16, i32, i64);
371
372macro_rules! as_brdb_float {
373    ($ty:ty, $($rest:ty),*) => {
374        as_brdb_float!($ty);
375        as_brdb_float!($($rest),*);
376    };
377    ($ty:ty) => {
378        impl AsBrdbValue for $ty {
379            fn as_brdb_f32(&self) -> Result<f32, BrdbSchemaError> {
380                Ok(*self as f32)
381            }
382            fn as_brdb_f64(&self) -> Result<f64, BrdbSchemaError> {
383                Ok(*self as f64)
384            }
385            fn as_brdb_wire_variant(
386                &self,
387            ) -> Result<WireVariant, BrdbSchemaError> {
388                Ok(WireVariant::Number(*self as f64))
389            }
390        }
391    };
392}
393as_brdb_float!(f32, f64);
394
395impl AsBrdbValue for bool {
396    fn as_brdb_bool(&self) -> Result<bool, BrdbSchemaError> {
397        Ok(*self)
398    }
399    fn as_brdb_wire_variant(&self) -> Result<crate::schema::value::WireVariant, BrdbSchemaError> {
400        Ok(WireVariant::Bool(*self))
401    }
402}
403impl AsBrdbValue for String {
404    fn as_brdb_str(&self) -> Result<&str, BrdbSchemaError> {
405        Ok(self)
406    }
407}
408impl AsBrdbValue for &str {
409    fn as_brdb_str(&self) -> Result<&str, BrdbSchemaError> {
410        Ok(self)
411    }
412}
413
414pub trait AsBrdbIter {
415    fn as_brdb_iter(&self) -> BrdbArrayIter;
416}
417pub trait AsBrdbMapIter {
418    fn as_brdb_map_iter(&self) -> BrdbMapIter;
419}
420
421impl<T: AsBrdbValue> AsBrdbIter for Vec<T> {
422    fn as_brdb_iter(&self) -> BrdbArrayIter {
423        Box::new(self.iter().map(|v| v as &dyn AsBrdbValue))
424    }
425}
426impl<T: AsBrdbValue> AsBrdbIter for IndexSet<T> {
427    fn as_brdb_iter(&self) -> BrdbArrayIter {
428        Box::new(self.iter().map(|v| v as &dyn AsBrdbValue))
429    }
430}
431impl<K: AsBrdbValue, V: AsBrdbValue> AsBrdbMapIter for IndexMap<K, V> {
432    fn as_brdb_map_iter(&self) -> BrdbMapIter {
433        Box::new(
434            self.iter()
435                .map(|(k, v)| (k as &dyn AsBrdbValue, v as &dyn AsBrdbValue)),
436        )
437    }
438}
439
440// Automatically implement `AsBrdbValue` for tuples of any number of elements
441// and treat them as struct properties.
442macro_rules! as_brdb_tuple {
443    ($($name:ident $index:tt),*) => {
444        impl<$($name: AsBrdbValue),*> AsBrdbValue for ($($name),*) {
445            fn as_brdb_struct_prop_value(
446                &self,
447                schema: &BrdbSchema,
448                struct_name: BrdbInterned,
449                prop_name: BrdbInterned,
450            ) -> Result<&dyn AsBrdbValue, BrdbSchemaError> {
451                let s_ty = schema.get_struct_interned(struct_name).unwrap();
452                let prop_index = s_ty.get_index_of(&prop_name);
453                match prop_index {
454                    $(
455                        Some($index) => Ok(&self.$index),
456                    )*
457                    _ => Err(BrdbSchemaError::MissingStructField(
458                        struct_name.get_or_else(schema, || "unknown struct".to_owned()),
459                        prop_name.get_or_else(schema, || "unknown property".to_owned()),
460                    )),
461                }
462            }
463        }
464    };
465}
466
467as_brdb_tuple!(A 0, B 1);
468as_brdb_tuple!(A 0, B 1, C 2);
469as_brdb_tuple!(A 0, B 1, C 2, D 3);
470as_brdb_tuple!(A 0, B 1, C 2, D 3, E 4);