+49
-39
crates/jacquard-common/src/types/value.rs
+49
-39
crates/jacquard-common/src/types/value.rs
···
28
28
Blob(Blob<'s>),
29
29
}
30
30
31
+
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, miette::Diagnostic)]
32
+
pub enum AtDataError {
33
+
#[error("floating point numbers not allowed in AT protocol data")]
34
+
FloatNotAllowed,
35
+
}
36
+
31
37
impl<'s> Data<'s> {
32
-
pub fn from_json(json: &'s serde_json::Value) -> Self {
33
-
if let Some(value) = json.as_bool() {
38
+
pub fn from_json(json: &'s serde_json::Value) -> Result<Self, AtDataError> {
39
+
Ok(if let Some(value) = json.as_bool() {
34
40
Self::Boolean(value)
35
41
} else if let Some(value) = json.as_i64() {
36
42
Self::Integer(value)
37
43
} else if let Some(value) = json.as_str() {
38
44
Self::String(AtprotoStr::new(value))
39
45
} else if let Some(value) = json.as_array() {
40
-
Self::Array(Array::from_json(value))
46
+
Self::Array(Array::from_json(value)?)
41
47
} else if let Some(value) = json.as_object() {
42
-
Object::from_json(value)
43
-
} else if let Some(num) = json.as_number() {
44
-
// deliberately permissive here, just in case.
45
-
Self::String(AtprotoStr::new_owned(num.to_smolstr()))
48
+
Object::from_json(value)?
49
+
} else if json.is_f64() {
50
+
return Err(AtDataError::FloatNotAllowed);
46
51
} else {
47
52
Self::Null
48
-
}
53
+
})
49
54
}
50
55
51
-
pub fn from_cbor(cbor: &'s Ipld) -> Self {
52
-
match cbor {
56
+
pub fn from_cbor(cbor: &'s Ipld) -> Result<Self, AtDataError> {
57
+
Ok(match cbor {
53
58
Ipld::Null => Data::Null,
54
59
Ipld::Bool(bool) => Data::Boolean(*bool),
55
60
Ipld::Integer(int) => Data::Integer(*int as i64),
56
-
Ipld::Float(_) => todo!(),
61
+
Ipld::Float(_) => {
62
+
return Err(AtDataError::FloatNotAllowed);
63
+
}
57
64
Ipld::String(string) => Self::String(AtprotoStr::new(string)),
58
65
Ipld::Bytes(items) => Self::Bytes(Bytes::copy_from_slice(items.as_slice())),
59
-
Ipld::List(iplds) => Self::Array(Array::from_cbor(iplds)),
60
-
Ipld::Map(btree_map) => Object::from_cbor(btree_map),
66
+
Ipld::List(iplds) => Self::Array(Array::from_cbor(iplds)?),
67
+
Ipld::Map(btree_map) => Object::from_cbor(btree_map)?,
61
68
Ipld::Link(cid) => Self::CidLink(Cid::ipld(*cid)),
62
-
}
69
+
})
63
70
}
64
71
}
65
72
···
67
74
pub struct Array<'s>(pub Vec<Data<'s>>);
68
75
69
76
impl<'s> Array<'s> {
70
-
pub fn from_json(json: &'s Vec<serde_json::Value>) -> Self {
77
+
pub fn from_json(json: &'s Vec<serde_json::Value>) -> Result<Self, AtDataError> {
71
78
let mut array = Vec::with_capacity(json.len());
72
79
for item in json {
73
-
array.push(Data::from_json(item));
80
+
array.push(Data::from_json(item)?);
74
81
}
75
-
Self(array)
82
+
Ok(Self(array))
76
83
}
77
-
pub fn from_cbor(cbor: &'s Vec<Ipld>) -> Self {
84
+
pub fn from_cbor(cbor: &'s Vec<Ipld>) -> Result<Self, AtDataError> {
78
85
let mut array = Vec::with_capacity(cbor.len());
79
86
for item in cbor {
80
-
array.push(Data::from_cbor(item));
87
+
array.push(Data::from_cbor(item)?);
81
88
}
82
-
Self(array)
89
+
Ok(Self(array))
83
90
}
84
91
}
85
92
···
87
94
pub struct Object<'s>(pub BTreeMap<SmolStr, Data<'s>>);
88
95
89
96
impl<'s> Object<'s> {
90
-
pub fn from_json(json: &'s serde_json::Map<String, serde_json::Value>) -> Data<'s> {
97
+
pub fn from_json(
98
+
json: &'s serde_json::Map<String, serde_json::Value>,
99
+
) -> Result<Data<'s>, AtDataError> {
91
100
if let Some(type_field) = json.get("$type").and_then(|v| v.as_str()) {
92
101
if infer_from_type(type_field) == DataModelType::Blob {
93
102
if let Some(blob) = json_to_blob(json) {
94
-
return Data::Blob(blob);
103
+
return Ok(Data::Blob(blob));
95
104
}
96
105
}
97
106
}
···
99
108
100
109
for (key, value) in json {
101
110
if key == "$type" {
102
-
map.insert(key.to_smolstr(), Data::from_json(value));
111
+
map.insert(key.to_smolstr(), Data::from_json(value)?);
103
112
}
104
113
match string_key_type_guess(key) {
105
114
DataModelType::Null if value.is_null() => {
···
119
128
if let Some(value) = value.get("$link").and_then(|v| v.as_str()) {
120
129
map.insert(key.to_smolstr(), Data::CidLink(Cid::Str(value.into())));
121
130
} else {
122
-
map.insert(key.to_smolstr(), Object::from_json(value));
131
+
map.insert(key.to_smolstr(), Object::from_json(value)?);
123
132
}
124
133
} else {
125
-
map.insert(key.to_smolstr(), Data::from_json(value));
134
+
map.insert(key.to_smolstr(), Data::from_json(value)?);
126
135
}
127
136
}
128
137
DataModelType::Blob if value.is_object() => {
129
138
map.insert(
130
139
key.to_smolstr(),
131
-
Object::from_json(value.as_object().unwrap()),
140
+
Object::from_json(value.as_object().unwrap())?,
132
141
);
133
142
}
134
143
DataModelType::Array if value.is_array() => {
135
144
map.insert(
136
145
key.to_smolstr(),
137
-
Data::Array(Array::from_json(value.as_array().unwrap())),
146
+
Data::Array(Array::from_json(value.as_array().unwrap())?),
138
147
);
139
148
}
140
149
DataModelType::Object if value.is_object() => {
141
150
map.insert(
142
151
key.to_smolstr(),
143
-
Object::from_json(value.as_object().unwrap()),
152
+
Object::from_json(value.as_object().unwrap())?,
144
153
);
145
154
}
146
155
DataModelType::String(string_type) if value.is_string() => {
147
156
insert_string(&mut map, key, value.as_str().unwrap(), string_type);
148
157
}
149
158
_ => {
150
-
map.insert(key.to_smolstr(), Data::from_json(value));
159
+
map.insert(key.to_smolstr(), Data::from_json(value)?);
151
160
}
152
161
}
153
162
}
154
163
155
-
Data::Object(Object(map))
164
+
Ok(Data::Object(Object(map)))
156
165
}
157
166
158
-
pub fn from_cbor(cbor: &'s BTreeMap<String, Ipld>) -> Data<'s> {
167
+
pub fn from_cbor(cbor: &'s BTreeMap<String, Ipld>) -> Result<Data<'s>, AtDataError> {
159
168
if let Some(Ipld::String(type_field)) = cbor.get("$type") {
160
169
if infer_from_type(type_field) == DataModelType::Blob {
161
170
if let Some(blob) = cbor_to_blob(cbor) {
162
-
return Data::Blob(blob);
171
+
return Ok(Data::Blob(blob));
163
172
}
164
173
}
165
174
}
···
167
176
168
177
for (key, value) in cbor {
169
178
if key == "$type" {
170
-
map.insert(key.to_smolstr(), Data::from_cbor(value));
179
+
map.insert(key.to_smolstr(), Data::from_cbor(value)?);
171
180
}
172
181
match (string_key_type_guess(key), value) {
173
182
(DataModelType::Null, Ipld::Null) => {
···
183
192
map.insert(key.to_smolstr(), Data::Bytes(Bytes::copy_from_slice(value)));
184
193
}
185
194
(DataModelType::Blob, Ipld::Map(value)) => {
186
-
map.insert(key.to_smolstr(), Object::from_cbor(value));
195
+
map.insert(key.to_smolstr(), Object::from_cbor(value)?);
187
196
}
188
197
(DataModelType::Array, Ipld::List(value)) => {
189
-
map.insert(key.to_smolstr(), Data::Array(Array::from_cbor(value)));
198
+
map.insert(key.to_smolstr(), Data::Array(Array::from_cbor(value)?));
190
199
}
191
200
(DataModelType::Object, Ipld::Map(value)) => {
192
-
map.insert(key.to_smolstr(), Object::from_cbor(value));
201
+
map.insert(key.to_smolstr(), Object::from_cbor(value)?);
193
202
}
194
203
(DataModelType::String(string_type), Ipld::String(value)) => {
195
204
insert_string(&mut map, key, value, string_type);
196
205
}
197
206
_ => {
198
-
map.insert(key.to_smolstr(), Data::from_cbor(value));
207
+
map.insert(key.to_smolstr(), Data::from_cbor(value)?);
199
208
}
200
209
}
201
210
}
202
211
203
-
Data::Object(Object(map))
212
+
Ok(Data::Object(Object(map)))
204
213
}
205
214
}
206
215
···
209
218
key: &'s str,
210
219
value: &'s str,
211
220
string_type: LexiconStringType,
212
-
) {
221
+
) -> Result<(), AtDataError> {
213
222
match string_type {
214
223
LexiconStringType::Datetime => {
215
224
if let Ok(datetime) = Datetime::from_str(value) {
···
334
343
map.insert(key.to_smolstr(), Data::String(parse_string(value)));
335
344
}
336
345
}
346
+
Ok(())
337
347
}
338
348
339
349
/// smarter parsing to avoid trying as many posibilities.