1use serde::{Deserialize, Serialize};
2use std::borrow::Cow;
3
4#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
12#[serde(tag = "type", content = "value")]
13pub enum Value {
14 Unit,
15 Bool(bool),
16 Int(i64),
17 Float(f64),
18 String(Cow<'static, str>),
19 Bytes(Cow<'static, [u8]>),
20 List(Vec<Value>),
21 Map(Vec<(Value, Value)>),
22 Tuple(Vec<Value>),
23 Struct(Vec<StructFieldValue>),
24 Enum(EnumValue),
25}
26
27#[derive(Clone, Debug, PartialEq)]
36pub enum ValueRef<'a> {
37 Unit,
38 Bool(bool),
39 Int(i64),
40 Float(f64),
41 String(&'a str),
42 Bytes(&'a [u8]),
43 List(&'a [Value]),
44 Map(&'a [(Value, Value)]),
45 Tuple(&'a [Value]),
46 Struct(&'a [StructFieldValue]),
47 Enum {
48 name: &'a str,
49 value: Option<&'a Value>,
50 },
51}
52
53impl<'a> From<&'a Value> for ValueRef<'a> {
54 fn from(v: &'a Value) -> Self {
55 match v {
56 Value::Unit => ValueRef::Unit,
57 Value::Bool(b) => ValueRef::Bool(*b),
58 Value::Int(i) => ValueRef::Int(*i),
59 Value::Float(f) => ValueRef::Float(*f),
60 Value::String(s) => ValueRef::String(s),
61 Value::Bytes(b) => ValueRef::Bytes(b),
62 Value::List(items) => ValueRef::List(items),
63 Value::Map(entries) => ValueRef::Map(entries),
64 Value::Tuple(items) => ValueRef::Tuple(items),
65 Value::Struct(fields) => ValueRef::Struct(fields),
66 Value::Enum(ev) => ValueRef::Enum {
67 name: &ev.name,
68 value: ev.value.as_deref(),
69 },
70 }
71 }
72}
73
74impl<'a> ValueRef<'a> {
75 pub fn into_owned(self) -> Value {
84 match self {
85 ValueRef::Unit => Value::Unit,
86 ValueRef::Bool(b) => Value::Bool(b),
87 ValueRef::Int(i) => Value::Int(i),
88 ValueRef::Float(f) => Value::Float(f),
89 ValueRef::String(s) => Value::String(Cow::Owned(s.to_string())),
90 ValueRef::Bytes(b) => Value::Bytes(Cow::Owned(b.to_vec())),
91 ValueRef::List(items) => Value::List(items.to_vec()),
92 ValueRef::Map(entries) => Value::Map(entries.to_vec()),
93 ValueRef::Tuple(items) => Value::Tuple(items.to_vec()),
94 ValueRef::Struct(fields) => Value::Struct(fields.to_vec()),
95 ValueRef::Enum { name, value } => Value::Enum(EnumValue {
96 name: name.to_string(),
97 value: value.map(|v| Box::new(v.clone())),
98 }),
99 }
100 }
101}
102
103#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord)]
111pub enum ValueType {
112 Unit,
113 Bool,
114 I32,
116 U32,
118 Int,
119 F32,
121 Float,
122 String,
123 Bytes,
124 }
126
127#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord)]
135pub enum TypeExpr {
136 Scalar(ValueType),
137 Opaque(String),
142 Optional(Box<TypeExpr>),
143 List(Box<TypeExpr>),
144 Map(Box<TypeExpr>, Box<TypeExpr>),
145 Tuple(Vec<TypeExpr>),
146 Struct(Vec<StructField>),
147 Enum(Vec<EnumVariant>),
148}
149
150impl TypeExpr {
151 pub fn scalar(t: ValueType) -> Self {
153 TypeExpr::Scalar(t)
154 }
155
156 pub fn opaque(name: impl Into<String>) -> Self {
158 TypeExpr::Opaque(name.into())
159 }
160
161 pub fn optional(inner: TypeExpr) -> Self {
163 TypeExpr::Optional(Box::new(inner))
164 }
165
166 pub fn list(inner: TypeExpr) -> Self {
168 TypeExpr::List(Box::new(inner))
169 }
170
171 pub fn map(key: TypeExpr, value: TypeExpr) -> Self {
173 TypeExpr::Map(Box::new(key), Box::new(value))
174 }
175
176 pub fn r#struct(fields: Vec<StructField>) -> Self {
178 TypeExpr::Struct(fields)
179 }
180
181 pub fn r#enum(variants: Vec<EnumVariant>) -> Self {
183 TypeExpr::Enum(variants)
184 }
185
186 pub fn normalize(self) -> Self {
188 match self {
189 TypeExpr::Scalar(v) => TypeExpr::Scalar(v),
190 TypeExpr::Opaque(name) => TypeExpr::Opaque(name),
191 TypeExpr::Optional(inner) => TypeExpr::Optional(Box::new(inner.normalize())),
192 TypeExpr::List(inner) => TypeExpr::List(Box::new(inner.normalize())),
193 TypeExpr::Map(k, v) => TypeExpr::Map(Box::new(k.normalize()), Box::new(v.normalize())),
194 TypeExpr::Tuple(items) => {
195 TypeExpr::Tuple(items.into_iter().map(|t| t.normalize()).collect())
196 }
197 TypeExpr::Struct(mut fields) => {
198 for f in &mut fields {
199 f.ty = f.ty.clone().normalize();
200 }
201 fields.sort_by(|a, b| a.name.cmp(&b.name));
202 TypeExpr::Struct(fields)
203 }
204 TypeExpr::Enum(mut variants) => {
205 for v in &mut variants {
206 if let Some(t) = &v.ty {
207 v.ty = Some(t.clone().normalize());
208 }
209 }
210 variants.sort_by(|a, b| a.name.cmp(&b.name));
211 TypeExpr::Enum(variants)
212 }
213 }
214 }
215}
216
217#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord)]
225pub struct StructField {
226 pub name: String,
227 pub ty: TypeExpr,
228}
229
230#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
238pub struct StructFieldValue {
239 pub name: String,
240 pub value: Value,
241}
242
243#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord)]
251pub struct EnumVariant {
252 pub name: String,
253 pub ty: Option<TypeExpr>,
254}
255
256#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
264pub struct EnumValue {
265 pub name: String,
266 pub value: Option<Box<Value>>,
267}
268
269#[cfg(test)]
270mod tests {
271 use super::*;
272
273 #[test]
274 fn struct_and_enum_ordering_are_deterministic() {
275 let a = TypeExpr::Struct(vec![
276 StructField {
277 name: "b".into(),
278 ty: TypeExpr::Scalar(ValueType::Bool),
279 },
280 StructField {
281 name: "a".into(),
282 ty: TypeExpr::Scalar(ValueType::Int),
283 },
284 ])
285 .normalize();
286 let fields = match a {
287 TypeExpr::Struct(f) => f,
288 _ => unreachable!(),
289 };
290 assert_eq!(fields[0].name, "a");
291
292 let variants = TypeExpr::Enum(vec![
293 EnumVariant {
294 name: "z".into(),
295 ty: None,
296 },
297 EnumVariant {
298 name: "a".into(),
299 ty: Some(TypeExpr::Scalar(ValueType::String)),
300 },
301 ])
302 .normalize();
303 let variants = match variants {
304 TypeExpr::Enum(v) => v,
305 _ => unreachable!(),
306 };
307 assert_eq!(variants[0].name, "a");
308 }
309
310 #[test]
311 fn value_ref_round_trip_owned() {
312 let v = Value::Struct(vec![
313 StructFieldValue {
314 name: "a".into(),
315 value: Value::Int(1),
316 },
317 StructFieldValue {
318 name: "b".into(),
319 value: Value::String("hi".into()),
320 },
321 ]);
322 let view = ValueRef::from(&v);
323 let owned = view.into_owned();
324 assert_eq!(v, owned);
325 }
326}