1use crate::{
2 error::Convert,
3 schema::{FieldSchema, Primitive, Schema, WithSchema},
4 types::{AttrStr, DictRef, ListRef, ObjectRef, Set, SetRef, TupleRef},
5};
6use indexmap::IndexMap;
7use serde::ser::Error;
8use serde::{
9 ser::{SerializeMap, SerializeSeq, Serializer},
10 Serialize,
11};
12
13lazy_static::lazy_static! {
14 static ref ATTR_NAME: AttrStr = AttrStr::new("name");
15 static ref ATTR_VALUE: AttrStr = AttrStr::new("value");
16}
17
18impl<'a> Serialize for WithSchema<'a> {
19 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
20 where
21 S: Serializer,
22 {
23 match self.schema {
24 Schema::Primitive(Primitive::Bool) => s.serialize_bool(self.object.as_bool().ser()?),
25 Schema::Primitive(Primitive::Int) => s.serialize_i64(self.object.as_i64().ser()?),
26 Schema::Primitive(Primitive::Str) => s.serialize_str(self.object.as_str().ser()?),
27 Schema::Primitive(Primitive::Float) => s.serialize_f64(self.object.as_f64().ser()?),
28 Schema::Primitive(Primitive::ByteArray) => {
29 s.serialize_bytes(self.object.as_bytearray().ser()?)
30 }
31 Schema::Primitive(Primitive::Bytes) => s.serialize_bytes(self.object.as_bytes().ser()?),
32 Schema::List(l) => {
33 let list = ListRef::new(self.object);
34 let len = list.len();
35 let mut seq = s.serialize_seq(Some(len))?;
36 for i in 0..len {
37 let obj = list.get(i).unwrap();
38 let w = obj.with_schema(&l.value);
39 seq.serialize_element(&w)?;
40 }
41 seq.end()
42 }
43 Schema::Set(l) => {
44 let set = SetRef::new(self.object);
45 let len = set.len();
46 let mut seq = s.serialize_seq(Some(len))?;
47
48 while let Some(item) = set.pop() {
49 let w = item.with_schema(&l.value);
50 seq.serialize_element(&w)?;
51 }
52 seq.end()
53 }
54 Schema::FrozenSet(l) => {
55 let set = Set::from_iter(self.object).ser()?;
56 let len = set.len();
57 let mut seq = s.serialize_seq(Some(len))?;
58
59 while let Some(item) = set.pop() {
60 let w = item.with_schema(&l.value);
61 seq.serialize_element(&w)?;
62 }
63 seq.end()
64 }
65 Schema::Tuple(t) => {
66 let tuple = TupleRef::new(self.object);
67 let iter = tuple.iter();
68 let len = iter.len();
69 let mut seq = s.serialize_seq(Some(len))?;
70 for (obj, schema) in iter.zip(t.args.iter()) {
71 let w = obj.with_schema(schema);
72 seq.serialize_element(&w)?;
73 }
74 seq.end()
75 }
76 Schema::Dict(d) => {
77 let dict = DictRef::new(self.object);
78 let mut map = s.serialize_map(Some(dict.len()))?;
79 for (k, v) in dict.iter() {
80 let k = k.with_schema(&d.key);
81 let v = v.with_schema(&d.value);
82 map.serialize_entry(&k, &v)?;
83 }
84 map.end()
85 }
86 Schema::Class(c) => {
87 let mut map = s.serialize_map(Some(c.fields.len()))?;
88 serialize_fields(&self.object, &c.fields, &mut map)?;
89 map.end()
90 }
91 Schema::Enum(e) => {
92 let name = self.object.get_attr(&ATTR_NAME).ser()?;
93 let name = name.as_str().ser()?;
94 if !e.variants.contains_key(name) {
95 return Err(S::Error::custom(format!("no such variant: {}", name)));
96 }
97 s.serialize_str(&name)
98 }
99 Schema::Optional(o) => {
100 if self.object.is_none() {
101 s.serialize_none()
102 } else {
103 let w = self.object.with_schema(&o.value);
104 s.serialize_some(&w)
105 }
106 }
107 Schema::Union(u) => {
108 let vs = self.object.get_type().ser()?.resolve(None).ser()?;
109 let vs = match u.variants.iter().find(|v| v == &vs) {
110 Some(vs) => vs,
111 None => return Err(S::Error::custom(format!("no such variant"))),
112 };
113 let v = self.object.with_schema(vs);
114 v.serialize(s)
115 }
116 Schema::Any(_) => self.object.resolved_object().ser()?.serialize(s),
117 }
118 }
119}
120
121fn serialize_fields<T, E>(
122 object: &ObjectRef,
123 fields: &IndexMap<String, FieldSchema>,
124 map: &mut T,
125) -> Result<(), E>
126where
127 T: SerializeMap<Error = E>,
128 E: serde::ser::Error,
129{
130 for (name, field) in fields {
131 let obj = object.get_attr(&field.name).ser()?;
132 if field.attr.flatten {
133 match &field.schema {
134 Schema::Class(cls) => {
135 serialize_fields(&obj, &cls.fields, map)?;
136 }
137 _ => return Err(E::custom(format!("found flatten flag for non-class type"))),
138 }
139 } else {
140 let f = obj.with_schema(&field.schema);
141 map.serialize_entry(&name, &f)?;
142 }
143 }
144 Ok(())
145}