1use reifydb_value::value::value_type::ValueType;
5use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as DeError, ser::Error as SerError};
6use serde_json::{Map, Value as JsonValue};
7
8#[derive(Debug, Clone, PartialEq)]
9pub struct WireValueType(pub ValueType);
10
11impl From<ValueType> for WireValueType {
12 fn from(ty: ValueType) -> Self {
13 Self(ty)
14 }
15}
16
17impl From<WireValueType> for ValueType {
18 fn from(wire: WireValueType) -> Self {
19 wire.0
20 }
21}
22
23const ID: &str = "id";
24const UNDERLYING: &str = "underlying";
25const NAME: &str = "name";
26const TYPE: &str = "type";
27
28fn scalar_id(ty: &ValueType) -> Option<&'static str> {
29 Some(match ty {
30 ValueType::Boolean => "Boolean",
31 ValueType::Float4 => "Float4",
32 ValueType::Float8 => "Float8",
33 ValueType::Int1 => "Int1",
34 ValueType::Int2 => "Int2",
35 ValueType::Int4 => "Int4",
36 ValueType::Int8 => "Int8",
37 ValueType::Int16 => "Int16",
38 ValueType::Utf8 => "Utf8",
39 ValueType::Uint1 => "Uint1",
40 ValueType::Uint2 => "Uint2",
41 ValueType::Uint4 => "Uint4",
42 ValueType::Uint8 => "Uint8",
43 ValueType::Uint16 => "Uint16",
44 ValueType::Date => "Date",
45 ValueType::DateTime => "DateTime",
46 ValueType::Time => "Time",
47 ValueType::Duration => "Duration",
48 ValueType::IdentityId => "IdentityId",
49 ValueType::Uuid4 => "Uuid4",
50 ValueType::Uuid7 => "Uuid7",
51 ValueType::Blob => "Blob",
52 ValueType::Int => "Int",
53 ValueType::Uint => "Uint",
54 ValueType::Decimal => "Decimal",
55 ValueType::Any => "Any",
56 ValueType::DictionaryId => "DictionaryId",
57 ValueType::Option(_) | ValueType::List(_) | ValueType::Record(_) | ValueType::Tuple(_) => {
58 return None;
59 }
60 })
61}
62
63fn scalar_from_id(id: &str) -> Option<ValueType> {
64 Some(match id {
65 "Boolean" => ValueType::Boolean,
66 "Float4" => ValueType::Float4,
67 "Float8" => ValueType::Float8,
68 "Int1" => ValueType::Int1,
69 "Int2" => ValueType::Int2,
70 "Int4" => ValueType::Int4,
71 "Int8" => ValueType::Int8,
72 "Int16" => ValueType::Int16,
73 "Utf8" => ValueType::Utf8,
74 "Uint1" => ValueType::Uint1,
75 "Uint2" => ValueType::Uint2,
76 "Uint4" => ValueType::Uint4,
77 "Uint8" => ValueType::Uint8,
78 "Uint16" => ValueType::Uint16,
79 "Date" => ValueType::Date,
80 "DateTime" => ValueType::DateTime,
81 "Time" => ValueType::Time,
82 "Duration" => ValueType::Duration,
83 "IdentityId" => ValueType::IdentityId,
84 "Uuid4" => ValueType::Uuid4,
85 "Uuid7" => ValueType::Uuid7,
86 "Blob" => ValueType::Blob,
87 "Int" => ValueType::Int,
88 "Uint" => ValueType::Uint,
89 "Decimal" => ValueType::Decimal,
90 "Any" => ValueType::Any,
91 "DictionaryId" => ValueType::DictionaryId,
92 _ => return None,
93 })
94}
95
96fn descriptor(id: &str, underlying: Option<JsonValue>) -> JsonValue {
97 let mut object = Map::new();
98 object.insert(ID.to_string(), JsonValue::String(id.to_string()));
99 if let Some(underlying) = underlying {
100 object.insert(UNDERLYING.to_string(), underlying);
101 }
102 JsonValue::Object(object)
103}
104
105pub fn to_json(ty: &ValueType) -> JsonValue {
106 if let Some(id) = scalar_id(ty) {
107 return descriptor(id, None);
108 }
109 match ty {
110 ValueType::Option(inner) => descriptor("Option", Some(to_json(inner))),
111 ValueType::List(inner) => descriptor("List", Some(to_json(inner))),
112 ValueType::Tuple(members) => {
113 descriptor("Tuple", Some(JsonValue::Array(members.iter().map(to_json).collect())))
114 }
115 ValueType::Record(fields) => {
116 let entries = fields
117 .iter()
118 .map(|(name, ty)| {
119 let mut field = Map::new();
120 field.insert(NAME.to_string(), JsonValue::String(name.clone()));
121 field.insert(TYPE.to_string(), to_json(ty));
122 JsonValue::Object(field)
123 })
124 .collect();
125 descriptor("Record", Some(JsonValue::Array(entries)))
126 }
127
128 other => descriptor(&other.to_string(), None),
129 }
130}
131
132pub fn from_json(value: &JsonValue) -> Result<ValueType, String> {
133 let object = value.as_object().ok_or_else(|| format!("expected a type descriptor object, got {value}"))?;
134 let id = object
135 .get(ID)
136 .and_then(JsonValue::as_str)
137 .ok_or_else(|| format!("type descriptor is missing a string `{ID}`: {value}"))?;
138 let underlying = object.get(UNDERLYING);
139
140 if let Some(scalar) = scalar_from_id(id) {
141 return Ok(scalar);
142 }
143
144 let child = || -> Result<ValueType, String> {
145 let underlying = underlying.ok_or_else(|| format!("`{id}` needs an `{UNDERLYING}` type: {value}"))?;
146 from_json(underlying)
147 };
148
149 match id {
150 "Option" => Ok(ValueType::Option(Box::new(child()?))),
151 "List" => Ok(ValueType::List(Box::new(child()?))),
152 "Tuple" => {
153 let members = underlying
154 .and_then(JsonValue::as_array)
155 .ok_or_else(|| format!("`Tuple` needs an `{UNDERLYING}` array: {value}"))?;
156 members.iter().map(from_json).collect::<Result<Vec<_>, _>>().map(ValueType::Tuple)
157 }
158 "Record" => {
159 let fields = underlying
160 .and_then(JsonValue::as_array)
161 .ok_or_else(|| format!("`Record` needs an `{UNDERLYING}` array: {value}"))?;
162 fields.iter()
163 .map(|field| {
164 let name = field
165 .get(NAME)
166 .and_then(JsonValue::as_str)
167 .ok_or_else(|| format!("record field is missing `{NAME}`: {field}"))?;
168 let ty = field
169 .get(TYPE)
170 .ok_or_else(|| format!("record field is missing `{TYPE}`: {field}"))?;
171 Ok((name.to_string(), from_json(ty)?))
172 })
173 .collect::<Result<Vec<_>, String>>()
174 .map(ValueType::Record)
175 }
176 unknown => Err(format!("unknown type id `{unknown}`")),
177 }
178}
179
180impl Serialize for WireValueType {
181 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
182 to_json(&self.0).serialize(serializer).map_err(S::Error::custom)
183 }
184}
185
186impl<'de> Deserialize<'de> for WireValueType {
187 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
188 let value = JsonValue::deserialize(deserializer)?;
189 from_json(&value).map(WireValueType).map_err(D::Error::custom)
190 }
191}