s2json_core/
value.rs

1use crate::Map;
2use alloc::{string::String, vec::Vec};
3use serde::{Deserialize, Serialize};
4
5/// Primitive types supported by Properties
6#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
7#[serde(untagged)]
8pub enum PrimitiveValue {
9    /// String type utf8 encoded
10    String(String),
11    /// unsigned 64 bit integer
12    U64(u64),
13    /// signed 64 bit integer
14    I64(i64),
15    /// floating point number
16    F32(f32),
17    /// double precision floating point number
18    F64(f64),
19    /// boolean
20    Bool(bool),
21    /// null
22    #[default]
23    Null,
24}
25
26/// Arrays may contain either a primitive or an object whose values are primitives
27#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
28#[serde(untagged)]
29pub enum ValuePrimitiveType {
30    /// Primitive type
31    Primitive(PrimitiveValue),
32    /// Nested shape that can only contain primitives
33    NestedPrimitive(ValuePrimitive),
34}
35
36/// Supports primitive types `string`, `number`, `boolean`, `null`
37/// May be an array of those types, or an object of those types
38/// Object keys are always strings, values can be any basic type, an array, or a nested object.
39/// Array values must all be the same type.
40#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
41#[serde(untagged)]
42pub enum ValueType {
43    /// A primitive value
44    Primitive(PrimitiveValue),
45    /// An array of values
46    Array(Vec<ValuePrimitiveType>),
47    /// A nested object
48    Nested(Value),
49}
50
51/// Shape of a ValuePrimitiveType Nested object
52pub type ValuePrimitive = Map<String, PrimitiveValue>;
53/// Shape design
54pub type Value = Map<String, ValueType>;
55/// Shape of a features properties object
56pub type Properties = Value;
57/// Shape of a feature's M-Values object
58pub type MValue = Value;
59
60/// Ensure M implements MValueCompatible
61pub trait MValueCompatible: From<MValue> + Into<MValue> + Clone + Default {}
62
63impl MValueCompatible for MValue {}
64
65/// LineString Properties Shape
66pub type LineStringMValues<M = MValue> = Vec<M>;
67/// MultiLineString MValues Shape
68pub type MultiLineStringMValues<M = MValue> = Vec<LineStringMValues<M>>;
69/// Polygon MValues Shape
70pub type PolygonMValues<M = MValue> = Vec<LineStringMValues<M>>;
71/// MultiPolygon MValues Shape
72pub type MultiPolygonMValues<M = MValue> = Vec<PolygonMValues<M>>;
73
74/// All possible M-Value shapes
75#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
76#[serde(untagged)]
77pub enum MValues<M: MValueCompatible = MValue> {
78    /// Single M-Value
79    MValue(M),
80    /// LineString M-Value
81    LineStringMValues(LineStringMValues<M>),
82    /// MultiLineString M-Value
83    MultiLineStringMValues(MultiLineStringMValues<M>),
84    /// Polygon M-Value
85    PolygonMValues(PolygonMValues<M>),
86    /// MultiPolygon M-Value
87    MultiPolygonMValues(MultiPolygonMValues<M>),
88}
89
90/// All possible JSON shapes
91#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
92#[serde(untagged)]
93pub enum JSONValue {
94    /// Represents a JSON primitive
95    Primitive(PrimitiveValue),
96    /// Represents a JSON array.
97    Array(Vec<JSONValue>),
98    /// Represents a JSON object.
99    Object(Map<String, JSONValue>),
100}
101
102/// Shape of an un-restricted features properties object
103pub type JSONProperties = Map<String, JSONValue>;
104
105/// Shape of the restricted Mapbox properties object
106pub type MapboxProperties = Map<String, PrimitiveValue>;
107
108#[cfg(test)]
109mod tests {
110    use super::*;
111
112    #[test]
113    fn json_value() {
114        let json_default = JSONValue::default();
115        assert_eq!(json_default, JSONValue::Primitive(PrimitiveValue::Null));
116
117        let json_default2: JSONValue = Default::default();
118        assert_eq!(json_default2, json_default);
119    }
120
121    #[test]
122    fn primitive_value() {
123        let prim_value = PrimitiveValue::String("test".into());
124        assert_eq!(prim_value, PrimitiveValue::String("test".into()));
125        let prim_value = PrimitiveValue::U64(1);
126        assert_eq!(prim_value, PrimitiveValue::U64(1));
127        let prim_value = PrimitiveValue::I64(1);
128        assert_eq!(prim_value, PrimitiveValue::I64(1));
129        let prim_value = PrimitiveValue::F32(1.0);
130        assert_eq!(prim_value, PrimitiveValue::F32(1.0));
131        let prim_value = PrimitiveValue::F64(1.0);
132        assert_eq!(prim_value, PrimitiveValue::F64(1.0));
133        let prim_value = PrimitiveValue::Bool(true);
134        assert_eq!(prim_value, PrimitiveValue::Bool(true));
135        let prim_value = PrimitiveValue::Null;
136        assert_eq!(prim_value, PrimitiveValue::Null);
137    }
138
139    #[test]
140    fn primitive_string_serialize() {
141        let prim_value = PrimitiveValue::String("test".into());
142        let serialized = serde_json::to_string(&prim_value).unwrap();
143        assert_eq!(serialized, "\"test\"");
144        let deserialize = serde_json::from_str::<PrimitiveValue>(&serialized).unwrap();
145        assert_eq!(deserialize, PrimitiveValue::String("test".into()));
146    }
147
148    #[test]
149    fn primitive_u64_serialize() {
150        let prim_value = PrimitiveValue::U64(1);
151        let serialized = serde_json::to_string(&prim_value).unwrap();
152        assert_eq!(serialized, "1");
153        let deserialize = serde_json::from_str::<PrimitiveValue>(&serialized).unwrap();
154        assert_eq!(deserialize, PrimitiveValue::U64(1));
155    }
156
157    #[test]
158    fn primitive_i64_serialize() {
159        let prim_value = PrimitiveValue::I64(-1);
160        let serialized = serde_json::to_string(&prim_value).unwrap();
161        assert_eq!(serialized, "-1");
162        let deserialize = serde_json::from_str::<PrimitiveValue>(&serialized).unwrap();
163        assert_eq!(deserialize, PrimitiveValue::I64(-1));
164    }
165
166    #[test]
167    fn primitive_f32_serialize() {
168        let prim_value = PrimitiveValue::F32(1.0);
169        let serialized = serde_json::to_string(&prim_value).unwrap();
170        assert_eq!(serialized, "1.0");
171        let deserialize = serde_json::from_str::<PrimitiveValue>(&serialized).unwrap();
172        assert_eq!(deserialize, PrimitiveValue::F32(1.0));
173    }
174
175    #[test]
176    fn primitive_f64_serialize() {
177        let prim_value = PrimitiveValue::F64(-135435345435345345.0);
178        let serialized = serde_json::to_string(&prim_value).unwrap();
179        assert_eq!(serialized, "-1.3543534543534534e17");
180        let deserialize = serde_json::from_str::<PrimitiveValue>(&serialized).unwrap();
181        assert_eq!(deserialize, PrimitiveValue::F32(-1.3543534e17));
182    }
183
184    #[test]
185    fn primitive_bool_serialize() {
186        let prim_value = PrimitiveValue::Bool(true);
187        let serialized = serde_json::to_string(&prim_value).unwrap();
188        assert_eq!(serialized, "true");
189        let deserialize = serde_json::from_str::<PrimitiveValue>(&serialized).unwrap();
190        assert_eq!(deserialize, PrimitiveValue::Bool(true));
191    }
192
193    #[test]
194    fn primitive_null_serialize() {
195        let prim_value = PrimitiveValue::Null;
196        let serialized = serde_json::to_string(&prim_value).unwrap();
197        assert_eq!(serialized, "null");
198        let deserialize = serde_json::from_str::<PrimitiveValue>(&serialized).unwrap();
199        assert_eq!(deserialize, PrimitiveValue::Null);
200    }
201
202    #[test]
203    fn value_default() {
204        let default = ValueType::default();
205        assert_eq!(default, ValueType::Primitive(PrimitiveValue::Null));
206
207        let default_instance: ValueType = Default::default();
208        assert_eq!(default, default_instance);
209    }
210
211    #[test]
212    fn value_serialize() {
213        let value = Value::from([
214            ("type".into(), ValueType::Primitive(PrimitiveValue::String("Point".into()))),
215            ("coordinates".into(), ValueType::Primitive(PrimitiveValue::F32(1.0))),
216        ]);
217        let serialized = serde_json::to_string(&value).unwrap();
218        assert_eq!(serialized, "{\"coordinates\":1.0,\"type\":\"Point\"}");
219        let deserialize = serde_json::from_str::<Value>(&serialized).unwrap();
220        assert_eq!(deserialize, value);
221
222        let value_str = r#"
223        {
224            "class": "ocean",
225            "offset": 22,
226            "info": {
227                "name": "Pacific Ocean",
228                "value": 22.2
229            }
230        }
231        "#;
232
233        let deserialize: MValue = serde_json::from_str::<Value>(value_str).unwrap();
234        assert_eq!(
235            deserialize,
236            Value::from([
237                ("class".into(), ValueType::Primitive(PrimitiveValue::String("ocean".into()))),
238                ("offset".into(), ValueType::Primitive(PrimitiveValue::U64(22))),
239                (
240                    "info".into(),
241                    ValueType::Nested(Value::from([
242                        (
243                            "name".into(),
244                            ValueType::Primitive(PrimitiveValue::String("Pacific Ocean".into()))
245                        ),
246                        ("value".into(), ValueType::Primitive(PrimitiveValue::F32(22.2))),
247                    ]))
248                ),
249            ])
250        );
251        let deserialize_to: MValue = deserialize.clone();
252        assert_eq!(deserialize_to, deserialize);
253        // from
254        let desrialize_from: MValue = MValue::from(deserialize_to);
255        assert_eq!(desrialize_from, deserialize);
256    }
257}