brdb/schema/
as_brdb.rs

1use indexmap::{IndexMap, IndexSet};
2
3use crate::{
4    errors::BrdbSchemaError,
5    schema::{BrdbInterned, BrdbSchema, BrdbSchemaEnum, BrdbStruct, 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        s.as_brdb_struct_prop_value(schema, struct_name, prop_name)
246    }
247    fn as_brdb_struct_prop_array(
248        &self,
249        schema: &BrdbSchema,
250        struct_name: BrdbInterned,
251        prop_name: BrdbInterned,
252    ) -> Result<BrdbArrayIter, BrdbSchemaError> {
253        let BrdbValue::Struct(s) = self else {
254            return Err(BrdbSchemaError::ExpectedType(
255                "struct".to_owned(),
256                self.get_type().to_string(),
257            ));
258        };
259        s.as_brdb_struct_prop_array(schema, struct_name, prop_name)
260    }
261    fn as_brdb_struct_prop_map(
262        &self,
263        schema: &BrdbSchema,
264        struct_name: BrdbInterned,
265        prop_name: BrdbInterned,
266    ) -> Result<BrdbMapIter, BrdbSchemaError> {
267        let BrdbValue::Struct(s) = self else {
268            return Err(BrdbSchemaError::ExpectedType(
269                "struct".to_owned(),
270                self.get_type().to_string(),
271            ));
272        };
273        s.as_brdb_struct_prop_map(schema, struct_name, prop_name)
274    }
275}
276
277impl AsBrdbValue for BrdbStruct {
278    fn as_brdb_struct_prop_value(
279        &self,
280        schema: &BrdbSchema,
281        _struct_name: BrdbInterned,
282        prop_name: BrdbInterned,
283    ) -> Result<&dyn AsBrdbValue, BrdbSchemaError> {
284        if let Some(prop) = self.properties.get(&prop_name) {
285            Ok(prop)
286        } else {
287            Err(BrdbSchemaError::MissingStructField(
288                schema
289                    .intern
290                    .lookup(self.name)
291                    .unwrap_or_else(|| "unknown struct".to_owned()),
292                schema
293                    .intern
294                    .lookup(prop_name)
295                    .unwrap_or_else(|| "unknown property".to_owned()),
296            ))
297        }
298    }
299
300    fn as_brdb_struct_prop_array(
301        &self,
302        schema: &BrdbSchema,
303        _struct_name: BrdbInterned,
304        prop_name: BrdbInterned,
305    ) -> Result<BrdbArrayIter, BrdbSchemaError> {
306        match self.properties.get(&prop_name) {
307            Some(BrdbValue::Array(vec)) | Some(BrdbValue::FlatArray(vec)) => Ok(vec.as_brdb_iter()),
308            _ => Err(BrdbSchemaError::MissingStructField(
309                schema
310                    .intern
311                    .lookup(self.name)
312                    .unwrap_or_else(|| "unknown struct".to_owned()),
313                schema
314                    .intern
315                    .lookup(prop_name)
316                    .unwrap_or_else(|| "unknown property".to_owned()),
317            )),
318        }
319    }
320
321    fn as_brdb_struct_prop_map(
322        &self,
323        schema: &BrdbSchema,
324        _struct_name: BrdbInterned,
325        prop_name: BrdbInterned,
326    ) -> Result<BrdbMapIter, BrdbSchemaError> {
327        if let Some(BrdbValue::Map(map)) = self.properties.get(&prop_name) {
328            Ok(Box::new(map.iter().map(|(k, v)| {
329                (k as &dyn AsBrdbValue, v as &dyn AsBrdbValue)
330            })))
331        } else {
332            Err(BrdbSchemaError::MissingStructField(
333                schema
334                    .intern
335                    .lookup(self.name)
336                    .unwrap_or_else(|| "unknown struct".to_owned()),
337                schema
338                    .intern
339                    .lookup(prop_name)
340                    .unwrap_or_else(|| "unknown property".to_owned()),
341            ))
342        }
343    }
344}
345
346impl AsBrdbValue for WireVariant {
347    fn as_brdb_wire_variant(&self) -> Result<WireVariant, BrdbSchemaError> {
348        Ok(self.clone())
349    }
350}
351
352macro_rules! as_brdb_int(
353    ($ty:ty, $($rest:ty),*) => {
354        as_brdb_int!($ty);
355        as_brdb_int!($($rest),*);
356    };
357    ($ty:ty) => {
358        impl AsBrdbValue for $ty {
359            fn as_brdb_bool(&self) -> Result<bool, BrdbSchemaError> {
360                Ok(*self != 0)
361            }
362            fn as_brdb_u8(&self) -> Result<u8, BrdbSchemaError> {
363                Ok(*self as u8)
364            }
365            fn as_brdb_u16(&self) -> Result<u16, BrdbSchemaError> {
366                Ok(*self as u16)
367            }
368            fn as_brdb_u32(&self) -> Result<u32, BrdbSchemaError> {
369                Ok(*self as u32)
370            }
371            fn as_brdb_u64(&self) -> Result<u64, BrdbSchemaError> {
372                Ok(*self as u64)
373            }
374            fn as_brdb_i8(&self) -> Result<i8, BrdbSchemaError> {
375                Ok(*self as i8)
376            }
377            fn as_brdb_i16(&self) -> Result<i16, BrdbSchemaError> {
378                Ok(*self as i16)
379            }
380            fn as_brdb_i32(&self) -> Result<i32, BrdbSchemaError> {
381                Ok(*self as i32)
382            }
383            fn as_brdb_i64(&self) -> Result<i64, BrdbSchemaError> {
384                Ok(*self as i64)
385            }
386            fn as_brdb_f32(&self) -> Result<f32, BrdbSchemaError> {
387                Ok(*self as f32)
388            }
389            fn as_brdb_f64(&self) -> Result<f64, BrdbSchemaError> {
390                Ok(*self as f64)
391            }
392            fn as_brdb_wire_variant(
393                &self,
394            ) -> Result<WireVariant, BrdbSchemaError> {
395                Ok((*self).into())
396            }
397        }
398    }
399);
400as_brdb_int!(u8, u16, u32, u64, i8, i16, i32, i64);
401
402macro_rules! as_brdb_float {
403    ($ty:ty, $($rest:ty),*) => {
404        as_brdb_float!($ty);
405        as_brdb_float!($($rest),*);
406    };
407    ($ty:ty) => {
408        impl AsBrdbValue for $ty {
409            fn as_brdb_f32(&self) -> Result<f32, BrdbSchemaError> {
410                Ok(*self as f32)
411            }
412            fn as_brdb_f64(&self) -> Result<f64, BrdbSchemaError> {
413                Ok(*self as f64)
414            }
415            fn as_brdb_wire_variant(
416                &self,
417            ) -> Result<WireVariant, BrdbSchemaError> {
418                Ok(WireVariant::Number(*self as f64))
419            }
420        }
421    };
422}
423as_brdb_float!(f32, f64);
424
425impl AsBrdbValue for bool {
426    fn as_brdb_bool(&self) -> Result<bool, BrdbSchemaError> {
427        Ok(*self)
428    }
429    fn as_brdb_wire_variant(&self) -> Result<crate::schema::value::WireVariant, BrdbSchemaError> {
430        Ok(WireVariant::Bool(*self))
431    }
432}
433impl AsBrdbValue for String {
434    fn as_brdb_str(&self) -> Result<&str, BrdbSchemaError> {
435        Ok(self)
436    }
437}
438impl AsBrdbValue for &str {
439    fn as_brdb_str(&self) -> Result<&str, BrdbSchemaError> {
440        Ok(self)
441    }
442}
443
444pub trait AsBrdbIter {
445    fn as_brdb_iter(&self) -> BrdbArrayIter;
446}
447pub trait AsBrdbMapIter {
448    fn as_brdb_map_iter(&self) -> BrdbMapIter;
449}
450
451impl<T: AsBrdbValue> AsBrdbIter for Vec<T> {
452    fn as_brdb_iter(&self) -> BrdbArrayIter {
453        Box::new(self.iter().map(|v| v as &dyn AsBrdbValue))
454    }
455}
456impl<T: AsBrdbValue> AsBrdbIter for IndexSet<T> {
457    fn as_brdb_iter(&self) -> BrdbArrayIter {
458        Box::new(self.iter().map(|v| v as &dyn AsBrdbValue))
459    }
460}
461impl<K: AsBrdbValue, V: AsBrdbValue> AsBrdbMapIter for IndexMap<K, V> {
462    fn as_brdb_map_iter(&self) -> BrdbMapIter {
463        Box::new(
464            self.iter()
465                .map(|(k, v)| (k as &dyn AsBrdbValue, v as &dyn AsBrdbValue)),
466        )
467    }
468}
469
470// Automatically implement `AsBrdbValue` for tuples of any number of elements
471// and treat them as struct properties.
472macro_rules! as_brdb_tuple {
473    ($($name:ident $index:tt),*) => {
474        impl<$($name: AsBrdbValue),*> AsBrdbValue for ($($name),*) {
475            fn as_brdb_struct_prop_value(
476                &self,
477                schema: &BrdbSchema,
478                struct_name: BrdbInterned,
479                prop_name: BrdbInterned,
480            ) -> Result<&dyn AsBrdbValue, BrdbSchemaError> {
481                let s_ty = schema.get_struct_interned(struct_name).unwrap();
482                let prop_index = s_ty.get_index_of(&prop_name);
483                match prop_index {
484                    $(
485                        Some($index) => Ok(&self.$index),
486                    )*
487                    _ => Err(BrdbSchemaError::MissingStructField(
488                        struct_name.get_or_else(schema, || "unknown struct".to_owned()),
489                        prop_name.get_or_else(schema, || "unknown property".to_owned()),
490                    )),
491                }
492            }
493        }
494    };
495}
496
497as_brdb_tuple!(A 0, B 1);
498as_brdb_tuple!(A 0, B 1, C 2);
499as_brdb_tuple!(A 0, B 1, C 2, D 3);
500as_brdb_tuple!(A 0, B 1, C 2, D 3, E 4);