1use crate::analysis::analysed_type::{list, option, record, tuple, variant};
16use crate::analysis::{
17 AnalysedResourceId, AnalysedResourceMode, AnalysedType, NameOptionTypePair, NameTypePair,
18 TypeEnum, TypeFlags, TypeHandle, TypeList, TypeOption, TypeRecord, TypeResult, TypeTuple,
19 TypeVariant,
20};
21use crate::json::ValueAndTypeJsonExtensions;
22use crate::{IntoValueAndType, Value, ValueAndType};
23use bigdecimal::{BigDecimal, FromPrimitive, ToPrimitive};
24use serde_json::{Number, Value as JsonValue};
25use std::collections::{HashMap, HashSet};
26use std::str::FromStr;
27
28impl ValueAndTypeJsonExtensions for ValueAndType {
29 fn parse_with_type(json_val: &JsonValue, typ: &AnalysedType) -> Result<Self, Vec<String>> {
30 match typ {
31 AnalysedType::Bool(_) => get_bool(json_val),
32 AnalysedType::S8(_) => get_s8(json_val),
33 AnalysedType::U8(_) => get_u8(json_val),
34 AnalysedType::S16(_) => get_s16(json_val),
35 AnalysedType::U16(_) => get_u16(json_val),
36 AnalysedType::S32(_) => get_s32(json_val),
37 AnalysedType::U32(_) => get_u32(json_val),
38 AnalysedType::S64(_) => get_s64(json_val),
39 AnalysedType::U64(_) => get_u64(json_val),
40 AnalysedType::F64(_) => get_f64(json_val),
41 AnalysedType::F32(_) => get_f32(json_val),
42 AnalysedType::Chr(_) => get_char(json_val),
43 AnalysedType::Str(_) => get_string(json_val),
44 AnalysedType::Enum(TypeEnum { cases, .. }) => get_enum(json_val, cases),
45 AnalysedType::Flags(TypeFlags { names, .. }) => get_flag(json_val, names),
46 AnalysedType::List(TypeList { inner, .. }) => get_list(json_val, inner),
47 AnalysedType::Option(TypeOption { inner, .. }) => get_option(json_val, inner),
48 AnalysedType::Result(TypeResult { ok, err, .. }) => get_result(json_val, ok, err),
49 AnalysedType::Record(TypeRecord { fields, .. }) => get_record(json_val, fields),
50 AnalysedType::Variant(TypeVariant { cases, .. }) => get_variant(json_val, cases),
51 AnalysedType::Tuple(TypeTuple { items, .. }) => get_tuple(json_val, items),
52 AnalysedType::Handle(TypeHandle {
53 resource_id, mode, ..
54 }) => get_handle(json_val, *resource_id, mode.clone()),
55 }
56 }
57
58 fn to_json_value(&self) -> Result<JsonValue, String> {
59 match (&self.typ, &self.value) {
60 (AnalysedType::Bool(_), Value::Bool(bool_val)) => Ok(JsonValue::Bool(*bool_val)),
61 (AnalysedType::S8(_), Value::S8(value)) => Ok(JsonValue::Number(Number::from(*value))),
62 (AnalysedType::U8(_), Value::U8(value)) => Ok(JsonValue::Number(Number::from(*value))),
63 (AnalysedType::S16(_), Value::S16(value)) => {
64 Ok(JsonValue::Number(Number::from(*value)))
65 }
66 (AnalysedType::U16(_), Value::U16(value)) => {
67 Ok(JsonValue::Number(Number::from(*value)))
68 }
69 (AnalysedType::S32(_), Value::S32(value)) => {
70 Ok(JsonValue::Number(Number::from(*value)))
71 }
72 (AnalysedType::U32(_), Value::U32(value)) => {
73 Ok(JsonValue::Number(Number::from(*value)))
74 }
75 (AnalysedType::S64(_), Value::S64(value)) => {
76 Ok(JsonValue::Number(Number::from(*value)))
77 }
78 (AnalysedType::U64(_), Value::U64(value)) => {
79 Ok(JsonValue::Number(Number::from(*value)))
80 }
81 (AnalysedType::F32(_), Value::F32(value)) => Ok(JsonValue::Number(
82 Number::from_f64(*value as f64)
83 .ok_or_else(|| "Failed to encode f32 as JSON number".to_string())?,
84 )),
85 (AnalysedType::F64(_), Value::F64(value)) => Ok(JsonValue::Number(
86 Number::from_f64(*value)
87 .ok_or_else(|| "Failed to encode f64 as JSON number".to_string())?,
88 )),
89 (AnalysedType::Chr(_), Value::Char(value)) => {
90 Ok(JsonValue::Number(Number::from(*value as u32)))
91 }
92 (AnalysedType::Str(_), Value::String(value)) => Ok(JsonValue::String(value.clone())),
93 (AnalysedType::Enum(TypeEnum { cases, .. }), Value::Enum(value)) => {
94 if let Some(case) = cases.get(*value as usize) {
95 Ok(JsonValue::String(case.clone()))
96 } else {
97 Err(format!("Invalid enum index '{value}'"))
98 }
99 }
100 (AnalysedType::Flags(TypeFlags { names, .. }), Value::Flags(value)) => {
101 let values: Vec<JsonValue> = value
102 .iter()
103 .zip(names)
104 .filter_map(|(enabled, name)| {
105 if *enabled {
106 Some(JsonValue::String(name.clone()))
107 } else {
108 None
109 }
110 })
111 .collect();
112 Ok(JsonValue::Array(values))
113 }
114 (AnalysedType::Option(TypeOption { inner, .. }), Value::Option(value)) => {
115 if let Some(inner_value) = value {
116 let inner_vnt = ValueAndType::new((**inner_value).clone(), (**inner).clone());
117 inner_vnt.to_json_value()
118 } else {
119 Ok(JsonValue::Null)
120 }
121 }
122 (AnalysedType::Tuple(TypeTuple { items, .. }), Value::Tuple(values)) => {
123 let item_jsons = items
124 .iter()
125 .zip(values)
126 .map(|(item_type, item_value)| {
127 let item_vnt = ValueAndType::new(item_value.clone(), item_type.clone());
128 item_vnt.to_json_value()
129 })
130 .collect::<Result<Vec<_>, _>>()?;
131 Ok(JsonValue::Array(item_jsons))
132 }
133 (AnalysedType::List(TypeList { inner, .. }), Value::List(values)) => {
134 let item_jsons = values
135 .iter()
136 .map(|item_value| {
137 let item_vnt = ValueAndType::new(item_value.clone(), (**inner).clone());
138 item_vnt.to_json_value()
139 })
140 .collect::<Result<Vec<_>, _>>()?;
141 Ok(JsonValue::Array(item_jsons))
142 }
143 (AnalysedType::Record(TypeRecord { fields, .. }), Value::Record(field_values)) => {
144 let fields = fields
145 .iter()
146 .zip(field_values)
147 .map(|(field_type, field_value)| {
148 let field_vnt =
149 ValueAndType::new(field_value.clone(), field_type.typ.clone());
150 field_vnt
151 .to_json_value()
152 .map(|json| (field_type.name.clone(), json))
153 })
154 .collect::<Result<Vec<_>, _>>()?;
155 Ok(JsonValue::Object(fields.into_iter().collect()))
156 }
157 (
158 AnalysedType::Variant(TypeVariant { cases, .. }),
159 Value::Variant {
160 case_idx,
161 case_value,
162 },
163 ) => {
164 if let Some(case) = cases.get(*case_idx as usize) {
165 let mut map = serde_json::Map::new();
166 match &case.typ {
167 Some(case_typ) => {
168 if let Some(value) = case_value {
169 let value_vnt =
170 ValueAndType::new((**value).clone(), case_typ.clone());
171 map.insert(case.name.clone(), value_vnt.to_json_value()?);
172 } else {
173 map.insert(case.name.clone(), JsonValue::Null);
174 }
175 }
176 None => {
177 map.insert(case.name.clone(), JsonValue::Null);
178 }
179 }
180 Ok(JsonValue::Object(map))
181 } else {
182 Err(format!("Invalid variant index '{case_idx}'"))
183 }
184 }
185 (AnalysedType::Result(TypeResult { ok, err, .. }), Value::Result(result)) => {
186 match result {
187 Ok(None) => Ok(JsonValue::Object(
188 vec![("ok".to_string(), JsonValue::Null)]
189 .into_iter()
190 .collect(),
191 )),
192 Ok(Some(ok_value)) => {
193 if let Some(ok_type) = ok {
194 let ok_vnt =
195 ValueAndType::new((**ok_value).clone(), (**ok_type).clone());
196 Ok(JsonValue::Object(
197 vec![("ok".to_string(), ok_vnt.to_json_value()?)]
198 .into_iter()
199 .collect(),
200 ))
201 } else {
202 Err("Missing ok value in Result".to_string())
203 }
204 }
205 Err(None) => Ok(JsonValue::Object(
206 vec![("err".to_string(), JsonValue::Null)]
207 .into_iter()
208 .collect(),
209 )),
210 Err(Some(err_value)) => {
211 if let Some(err_type) = err {
212 let err_vnt =
213 ValueAndType::new((**err_value).clone(), (**err_type).clone());
214 Ok(JsonValue::Object(
215 vec![("err".to_string(), err_vnt.to_json_value()?)]
216 .into_iter()
217 .collect(),
218 ))
219 } else {
220 Err("Missing err value in Result".to_string())
221 }
222 }
223 }
224 }
225 (AnalysedType::Handle(TypeHandle { .. }), Value::Handle { uri, resource_id }) => {
226 Ok(JsonValue::String(format!("{uri}/{resource_id}")))
227 }
228 _ => Err(format!(
229 "Type and value mismatch (type is {:?}, value is {:?})",
230 self.typ, self.value
231 )),
232 }
233 }
234}
235
236fn get_bool(json: &JsonValue) -> Result<ValueAndType, Vec<String>> {
237 match json {
238 JsonValue::Bool(bool_val) => Ok(bool_val.into_value_and_type()),
239 _ => {
240 let type_description = type_description(json);
241 Err(vec![format!("expected bool, found {}", type_description)])
242 }
243 }
244}
245
246fn get_s8(json: &JsonValue) -> Result<ValueAndType, Vec<String>> {
247 ensure_range(
248 json,
249 BigDecimal::from_i8(i8::MIN).expect("Failed to convert i8::MIN to BigDecimal"),
250 BigDecimal::from_i8(i8::MAX).expect("Failed to convert i8::MAX to BigDecimal"),
251 )
252 .and_then(|num| {
253 num.to_i8()
254 .ok_or_else(|| vec!["Failed to convert number to i8".to_string()])
255 })
256 .map(|num| num.into_value_and_type())
257}
258
259fn get_u8(json: &JsonValue) -> Result<ValueAndType, Vec<String>> {
260 ensure_range(
261 json,
262 BigDecimal::from_u8(u8::MIN).expect("Failed to convert u8::MIN to BigDecimal"),
263 BigDecimal::from_u8(u8::MAX).expect("Failed to convert u8::MAX to BigDecimal"),
264 )
265 .and_then(|num| {
266 num.to_u8()
267 .ok_or_else(|| vec!["Failed to convert number to u8".to_string()])
268 })
269 .map(|num| num.into_value_and_type())
270}
271
272fn get_s16(json: &JsonValue) -> Result<ValueAndType, Vec<String>> {
273 ensure_range(
274 json,
275 BigDecimal::from_i16(i16::MIN).expect("Failed to convert i16::MIN to BigDecimal"),
276 BigDecimal::from_i16(i16::MAX).expect("Failed to convert i16::MAX to BigDecimal"),
277 )
278 .and_then(|num| {
279 num.to_i16()
280 .ok_or_else(|| vec!["Failed to convert number to i16".to_string()])
281 })
282 .map(|num| num.into_value_and_type())
283}
284
285fn get_u16(json: &JsonValue) -> Result<ValueAndType, Vec<String>> {
286 ensure_range(
287 json,
288 BigDecimal::from_u16(u16::MIN).expect("Failed to convert u16::MIN to BigDecimal"),
289 BigDecimal::from_u16(u16::MAX).expect("Failed to convert u16::MAX to BigDecimal"),
290 )
291 .and_then(|num| {
292 num.to_u16()
293 .ok_or_else(|| vec!["Failed to convert number to u16".to_string()])
294 })
295 .map(|num| num.into_value_and_type())
296}
297
298fn get_s32(json: &JsonValue) -> Result<ValueAndType, Vec<String>> {
299 ensure_range(
300 json,
301 BigDecimal::from_i32(i32::MIN).expect("Failed to convert i32::MIN to BigDecimal"),
302 BigDecimal::from_i32(i32::MAX).expect("Failed to convert i32::MAX to BigDecimal"),
303 )
304 .and_then(|num| {
305 num.to_i32()
306 .ok_or_else(|| vec!["Failed to convert number to i32".to_string()])
307 })
308 .map(|num| num.into_value_and_type())
309}
310
311fn get_u32(json: &JsonValue) -> Result<ValueAndType, Vec<String>> {
312 ensure_range(
313 json,
314 BigDecimal::from_u32(u32::MIN).expect("Failed to convert u32::MIN to BigDecimal"),
315 BigDecimal::from_u32(u32::MAX).expect("Failed to convert u32::MAX to BigDecimal"),
316 )
317 .and_then(|num| {
318 num.to_u32()
319 .ok_or_else(|| vec!["Failed to convert number to u32".to_string()])
320 })
321 .map(|num| num.into_value_and_type())
322}
323
324fn get_s64(json: &JsonValue) -> Result<ValueAndType, Vec<String>> {
325 ensure_range(
326 json,
327 BigDecimal::from_i64(i64::MIN).expect("Failed to convert i64::MIN to BigDecimal"),
328 BigDecimal::from_i64(i64::MAX).expect("Failed to convert i64::MAX to BigDecimal"),
329 )
330 .and_then(|num| {
331 num.to_i64()
332 .ok_or_else(|| vec!["Failed to convert number to i64".to_string()])
333 })
334 .map(|num| num.into_value_and_type())
335}
336
337fn get_f32(json: &JsonValue) -> Result<ValueAndType, Vec<String>> {
338 ensure_range(
339 json,
340 BigDecimal::from_f32(f32::MIN).expect("Failed to convert f32::MIN to BigDecimal"),
341 BigDecimal::from_f32(f32::MAX).expect("Failed to convert f32::MAX to BigDecimal"),
342 )
343 .and_then(|num| {
344 num.to_f32()
345 .ok_or_else(|| vec!["Failed to convert number to f32".to_string()])
346 })
347 .map(|num| num.into_value_and_type())
348}
349
350fn get_f64(json_val: &JsonValue) -> Result<ValueAndType, Vec<String>> {
351 let num = get_big_decimal(json_val)?;
352 let num: f64 = num
353 .to_string()
354 .parse()
355 .map_err(|err| vec![format!("Failed to convert number to f64: {err}")])?;
356 Ok(num.into_value_and_type())
357}
358
359fn get_string(json: &JsonValue) -> Result<ValueAndType, Vec<String>> {
360 if let Some(str_value) = json.as_str() {
361 Ok(str_value.to_string().into_value_and_type())
363 } else {
364 let type_description = type_description(json);
366 Err(vec![format!("expected string, found {}", type_description)])
367 }
368}
369
370fn get_char(json: &JsonValue) -> Result<ValueAndType, Vec<String>> {
371 if let Some(num_u64) = json.as_u64() {
372 if num_u64 > u32::MAX as u64 {
373 Err(vec![format!(
374 "The value {} is too large to be converted to a char",
375 num_u64
376 )])
377 } else if let Some(ch) = char::from_u32(num_u64 as u32) {
378 Ok(ch.into_value_and_type())
379 } else {
380 Err(vec![format!(
381 "The value {} cannot be converted to a char",
382 num_u64
383 )])
384 }
385 } else {
386 let type_description = type_description(json);
387
388 Err(vec![format!("expected char, found {}", type_description)])
389 }
390}
391
392fn get_tuple(input_json: &JsonValue, types: &[AnalysedType]) -> Result<ValueAndType, Vec<String>> {
393 let json_array = input_json.as_array().ok_or(vec![format!(
394 "Input {} is not an array representing tuple",
395 input_json
396 )])?;
397
398 if json_array.len() != types.len() {
399 return Err(vec![format!(
400 "The length of types in template is not equal to the length of tuple (array) in {}",
401 input_json,
402 )]);
403 }
404
405 let mut errors: Vec<String> = vec![];
406 let mut vals: Vec<Value> = vec![];
407 let mut tpes: Vec<AnalysedType> = vec![];
408
409 for (json, tpe) in json_array.iter().zip(types.iter()) {
410 match ValueAndType::parse_with_type(json, tpe) {
411 Ok(result) => {
412 vals.push(result.value);
413 tpes.push(result.typ);
414 }
415 Err(errs) => errors.extend(errs),
416 }
417 }
418
419 if errors.is_empty() {
420 Ok(ValueAndType::new(Value::Tuple(vals), tuple(tpes)))
421 } else {
422 Err(errors)
423 }
424}
425
426fn get_option(input_json: &JsonValue, tpe: &AnalysedType) -> Result<ValueAndType, Vec<String>> {
427 match input_json.as_null() {
428 Some(_) => Ok(ValueAndType::new(Value::Option(None), option(tpe.clone()))),
429
430 None => ValueAndType::parse_with_type(input_json, tpe).map(|result| {
431 ValueAndType::new(
432 Value::Option(Some(Box::new(result.value))),
433 option(tpe.clone()),
434 )
435 }),
436 }
437}
438
439fn get_list(input_json: &JsonValue, tpe: &AnalysedType) -> Result<ValueAndType, Vec<String>> {
440 let json_array = input_json
441 .as_array()
442 .ok_or(vec![format!("Input {} is not an array", input_json)])?;
443
444 let mut errors: Vec<String> = vec![];
445 let mut vals: Vec<Value> = vec![];
446
447 for json in json_array {
448 match ValueAndType::parse_with_type(json, tpe) {
449 Ok(result) => vals.push(result.value),
450 Err(errs) => errors.extend(errs),
451 }
452 }
453
454 if errors.is_empty() {
455 Ok(ValueAndType::new(Value::List(vals), list(tpe.clone())))
456 } else {
457 Err(errors)
458 }
459}
460
461fn get_enum(input_json: &JsonValue, names: &[String]) -> Result<ValueAndType, Vec<String>> {
462 let input_enum_value = input_json
463 .as_str()
464 .ok_or(vec![format!("Input {} is not string", input_json)])?;
465
466 let enum_value = names
467 .iter()
468 .position(|n| n == input_enum_value)
469 .ok_or_else(|| {
470 vec![format!(
471 "Invalid input {}. Valid values are {}",
472 input_enum_value,
473 names.join(",")
474 )]
475 })?;
476
477 Ok(ValueAndType::new(
478 Value::Enum(enum_value as u32),
479 AnalysedType::Enum(TypeEnum {
480 name: None,
481 owner: None,
482 cases: names.to_vec(),
483 }),
484 ))
485}
486
487#[allow(clippy::type_complexity)]
488fn get_result(
489 input_json: &JsonValue,
490 ok_type: &Option<Box<AnalysedType>>,
491 err_type: &Option<Box<AnalysedType>>,
492) -> Result<ValueAndType, Vec<String>> {
493 fn validate(
494 typ: &Option<Box<AnalysedType>>,
495 input_json: &JsonValue,
496 ) -> Result<Option<Box<Value>>, Vec<String>> {
497 if let Some(typ) = typ {
498 ValueAndType::parse_with_type(input_json, typ).map(|v| Some(Box::new(v.value)))
499 } else if input_json.is_null() {
500 Ok(None)
501 } else {
502 Err(vec![
503 "The type of ok is absent, but some JSON value was provided".to_string(),
504 ])
505 }
506 }
507
508 match input_json.get("ok") {
509 Some(value) => {
510 let value = validate(ok_type, value)?;
511
512 Ok(ValueAndType::new(
513 Value::Result(Ok(value)),
514 AnalysedType::Result(TypeResult {
515 ok: ok_type.clone(),
516 err: err_type.clone(),
517 name: None,
518 owner: None,
519 }),
520 ))
521 }
522 None => match input_json.get("err") {
523 Some(value) => {
524 let value = validate(err_type, value)?;
525
526 Ok(ValueAndType::new(
527 Value::Result(Err(value)),
528 AnalysedType::Result(TypeResult {
529 ok: ok_type.clone(),
530 err: err_type.clone(),
531 name: None,
532 owner: None,
533 }),
534 ))
535 }
536 None => Err(vec![
537 "Failed to retrieve either ok value or err value".to_string()
538 ]),
539 },
540 }
541}
542
543fn get_record(
544 input_json: &JsonValue,
545 name_type_pairs: &[NameTypePair],
546) -> Result<ValueAndType, Vec<String>> {
547 let json_map = input_json.as_object().ok_or(vec![format!(
548 "The input {} is not a json object",
549 input_json
550 )])?;
551
552 let mut errors: Vec<String> = vec![];
553 let mut vals: Vec<Value> = vec![];
554
555 for NameTypePair { name, typ } in name_type_pairs {
556 if let Some(json_value) = json_map.get(name) {
557 match ValueAndType::parse_with_type(json_value, typ) {
558 Ok(result) => vals.push(result.value),
559 Err(value_errors) => errors.extend(
560 value_errors
561 .iter()
562 .map(|err| format!("invalid value for key {name}: {err}"))
563 .collect::<Vec<_>>(),
564 ),
565 }
566 } else {
567 match typ {
568 AnalysedType::Option(_) => {
569 vals.push(Value::Option(None));
570 }
571 _ => errors.push(format!("key '{name}' not found")),
572 }
573 }
574 }
575
576 if errors.is_empty() {
577 Ok(ValueAndType::new(
578 Value::Record(vals),
579 record(name_type_pairs.to_vec()),
580 ))
581 } else {
582 Err(errors)
583 }
584}
585
586fn get_flag(input_json: &JsonValue, names: &[String]) -> Result<ValueAndType, Vec<String>> {
587 let json_array = input_json
588 .as_array()
589 .ok_or(vec![format!("Input {} is not an array", input_json)])?;
590
591 let mut errors: Vec<String> = vec![];
592 let mut vals: HashSet<String> = HashSet::new();
593
594 for json in json_array.iter() {
595 let flag: String = json
596 .as_str()
597 .map(|x| x.to_string())
598 .or_else(|| json.as_bool().map(|b| b.to_string()))
599 .or_else(|| json.as_number().map(|n| n.to_string()))
600 .ok_or(vec![format!(
601 "Input {} is not a string or boolean or number",
602 json
603 )])?;
604
605 if names.contains(&flag) {
606 vals.insert(flag);
607 } else {
608 errors.push(format!(
609 "Invalid input {}. Valid values are {}",
610 flag,
611 names.join(",")
612 ));
613 }
614 }
615
616 if errors.is_empty() {
617 let mut bitmap = vec![false; names.len()];
618 for (i, name) in names.iter().enumerate() {
619 bitmap[i] = vals.contains(name);
620 }
621
622 Ok(ValueAndType::new(
623 Value::Flags(bitmap),
624 AnalysedType::Flags(TypeFlags {
625 names: names.to_vec(),
626 name: None,
627 owner: None,
628 }),
629 ))
630 } else {
631 Err(errors)
632 }
633}
634
635fn get_variant(
636 input_json: &JsonValue,
637 types: &[NameOptionTypePair],
638) -> Result<ValueAndType, Vec<String>> {
639 let mut possible_mapping_indexed: HashMap<&String, &Option<AnalysedType>> = HashMap::new();
640
641 for NameOptionTypePair {
642 name,
643 typ: optional_type,
644 } in types.iter()
645 {
646 possible_mapping_indexed.insert(name, optional_type);
647 }
648
649 let json_obj = input_json
650 .as_object()
651 .ok_or(vec![format!("Input {} is not an object", input_json)])?;
652
653 let (key, json) = if json_obj.is_empty() {
654 Err(vec!["Zero variants in in the input".to_string()])
655 } else {
656 Ok(json_obj.iter().next().unwrap())
657 }?;
658
659 let case_idx = types
660 .iter()
661 .position(|pair| pair.name == *key)
662 .ok_or_else(|| vec![format!("Unknown key {key} in the variant")])?
663 as u32;
664
665 match possible_mapping_indexed.get(key) {
666 Some(Some(tpe)) => {
667 let result = ValueAndType::parse_with_type(json, tpe)?;
668
669 Ok(ValueAndType::new(
670 Value::Variant {
671 case_idx,
672 case_value: Some(Box::new(result.value)),
673 },
674 variant(types.to_vec()),
675 ))
676 }
677 Some(None) if json.is_null() => Ok(ValueAndType::new(
678 Value::Variant {
679 case_idx,
680 case_value: None,
681 },
682 variant(types.to_vec()),
683 )),
684 Some(None) => Err(vec![format!("Unit variant {key} has non-null JSON value")]),
685 None => Err(vec![format!("Unknown key {key} in the variant")]),
686 }
687}
688
689fn get_handle(
690 value: &JsonValue,
691 id: AnalysedResourceId,
692 resource_mode: AnalysedResourceMode,
693) -> Result<ValueAndType, Vec<String>> {
694 match value.as_str() {
695 Some(str) => {
696 let parts: Vec<&str> = str.split('/').collect();
698 if parts.len() >= 2 {
699 match u64::from_str(parts[parts.len() - 1]) {
700 Ok(resource_id) => {
701 let uri = parts[0..(parts.len() - 1)].join("/");
702
703 Ok(ValueAndType::new(
704 Value::Handle { resource_id, uri },
705 AnalysedType::Handle(TypeHandle {
706 resource_id: id,
707 mode: resource_mode,
708 name: None,
709 owner: None,
710 }),
711 ))
712 }
713 Err(err) => Err(vec![format!(
714 "Failed to parse resource-id section of the handle value: {}",
715 err
716 )]),
717 }
718 } else {
719 Err(vec![format!(
720 "expected handle, represented by a worker-url/resource-id string, found {}",
721 str
722 )])
723 }
724 }
725 None => Err(vec![format!(
726 "expected handle, represented by a worker-url/resource-id string, found {}",
727 type_description(value)
728 )]),
729 }
730}
731
732fn type_description(value: &JsonValue) -> &'static str {
733 match value {
734 JsonValue::Null => "null",
735 JsonValue::Bool(_) => "boolean",
736 JsonValue::Number(_) => "number",
737 JsonValue::String(_) => "string",
738 JsonValue::Array(_) => "list",
739 JsonValue::Object(_) => "record",
740 }
741}
742
743fn ensure_range(
744 value: &JsonValue,
745 min: BigDecimal,
746 max: BigDecimal,
747) -> Result<BigDecimal, Vec<String>> {
748 let num = get_big_decimal(value)?;
749 if num >= min && num <= max {
750 Ok(num)
751 } else {
752 Err(vec![format!(
753 "value {} is not within the range of {} to {}",
754 value, min, max
755 )])
756 }
757}
758
759fn get_big_decimal(value: &JsonValue) -> Result<BigDecimal, Vec<String>> {
760 match value {
761 JsonValue::Number(num) => {
762 if let Ok(f64) = BigDecimal::from_str(num.to_string().as_str()) {
763 Ok(f64)
764 } else {
765 Err(vec![format!("cannot convert {} to f64", num)])
766 }
767 }
768 _ => {
769 let type_description = type_description(value);
770 Err(vec![format!("expected number, found {}", type_description)])
771 }
772 }
773}
774
775fn get_u64(value: &JsonValue) -> Result<ValueAndType, Vec<String>> {
776 match value {
777 JsonValue::Number(num) => {
778 if let Some(u64) = num.as_u64() {
779 Ok(u64.into_value_and_type())
780 } else {
781 Err(vec![format!("Cannot convert {} to u64", num)])
782 }
783 }
784 _ => {
785 let type_description = type_description(value);
786 Err(vec![format!("expected u64, found {}", type_description)])
787 }
788 }
789}
790
791#[cfg(test)]
792mod tests {
793 use test_r::test;
794
795 use std::collections::HashSet;
796
797 use crate::analysis::analysed_type::{
798 bool, case, chr, f32, f64, field, flags, list, option, r#enum, record, result, s16, s32,
799 s64, s8, str, tuple, u16, u32, u64, u8, variant,
800 };
801 use crate::analysis::AnalysedType;
802 use proptest::prelude::*;
803 use serde_json::{Number, Value as JsonValue};
804
805 use crate::json::ValueAndTypeJsonExtensions;
806 use crate::{Value, ValueAndType};
807
808 fn validate_function_result(
809 val: Value,
810 expected_type: &AnalysedType,
811 ) -> Result<JsonValue, Vec<String>> {
812 ValueAndType::new(val, expected_type.clone())
813 .to_json_value()
814 .map_err(|s| vec![s])
815 }
816
817 fn validate_function_parameter(
818 json: &JsonValue,
819 expected_type: &AnalysedType,
820 ) -> Result<Value, Vec<String>> {
821 match ValueAndType::parse_with_type(json, expected_type) {
822 Ok(result) => Ok(result.value),
823 Err(err) => Err(err),
824 }
825 }
826
827 proptest! {
828 #[test]
829 fn test_u8_param(value: u8) {
830 let json = JsonValue::Number(Number::from(value));
831 let result = validate_function_parameter(&json, &u8());
832 prop_assert_eq!(result, Ok(Value::U8(value)));
833 }
834
835 #[test]
836 fn test_u16_param(value: u16) {
837 let json = JsonValue::Number(Number::from(value));
838 let result = validate_function_parameter(&json, &u16());
839 prop_assert_eq!(result, Ok(Value::U16(value)));
840 }
841
842 #[test]
843 fn test_u32_param(value: u32) {
844 let json = JsonValue::Number(Number::from(value));
845 let result = validate_function_parameter(&json, &u32());
846 prop_assert_eq!(result, Ok(Value::U32(value)));
847 }
848
849 #[test]
850 fn test_u64_param(value: u64) {
851 let json = JsonValue::Number(Number::from(value));
852 let result = validate_function_parameter(&json, &u64());
853 prop_assert_eq!(result, Ok(Value::U64(value)));
854 }
855
856 #[test]
857 fn test_s8_param(value: i8) {
858 let json = JsonValue::Number(Number::from(value));
859 let result = validate_function_parameter(&json, &s8());
860 prop_assert_eq!(result, Ok(Value::S8(value)));
861 }
862
863 #[test]
864 fn test_s16_param(value: i16) {
865 let json = JsonValue::Number(Number::from(value));
866 let result = validate_function_parameter(&json, &s16());
867 prop_assert_eq!(result, Ok(Value::S16(value)));
868 }
869
870 #[test]
871 fn test_s32_param(value: i32) {
872 let json = JsonValue::Number(Number::from(value));
873 let result = validate_function_parameter(&json, &s32());
874 prop_assert_eq!(result, Ok(Value::S32(value)));
875 }
876
877 #[test]
878 fn test_s64_param(value: i64) {
879 let json = JsonValue::Number(Number::from(value));
880 let result = validate_function_parameter(&json, &s64());
881 prop_assert_eq!(result, Ok(Value::S64(value)));
882 }
883
884 #[test]
885 fn test_f32_param(value: f32) {
886 let json = JsonValue::Number(Number::from_f64(value as f64).unwrap());
887 let result = validate_function_parameter(&json, &f32());
888 prop_assert_eq!(result, Ok(Value::F32(value)));
889 }
890
891 #[test]
892 fn test_f64_param(value: f64) {
893 let json = JsonValue::Number(Number::from_f64(value).unwrap());
894 let result = validate_function_parameter(&json, &f64());
895 prop_assert_eq!(result, Ok(Value::F64(value)));
896 }
897
898 #[test]
899 fn test_char_param(value: char) {
900 let json = JsonValue::Number(Number::from(value as u32));
901 let result = validate_function_parameter(&json, &chr());
902 prop_assert_eq!(result, Ok(Value::Char(value)));
903 }
904
905 #[test]
906 fn test_string_param(value: String) {
907 let json = JsonValue::String(value.clone());
908 let result = validate_function_parameter(&json, &str());
909 prop_assert_eq!(result, Ok(Value::String(value)));
910 }
911
912 #[test]
913 fn test_list_u8_param(value: Vec<u8>) {
914 let json = JsonValue::Array(value.iter().map(|v| JsonValue::Number(Number::from(*v))).collect());
915 let result = validate_function_parameter(&json, &list(u8()));
916 prop_assert_eq!(result, Ok(Value::List(value.into_iter().map(Value::U8).collect())));
917 }
918
919 #[test]
920 fn test_list_list_u64_param(value: Vec<Vec<u64>>) {
921 let json = JsonValue::Array(value.iter().map(|v| JsonValue::Array(v.iter().map(|n| JsonValue::Number(Number::from(*n))).collect())).collect());
922 let result = validate_function_parameter(&json, &list(list(u64())));
923 prop_assert_eq!(result, Ok(Value::List(value.into_iter().map(|v| Value::List(v.into_iter().map(Value::U64).collect())).collect())));
924 }
925
926 #[test]
927 fn test_tuple_int_char_string_param(value: (i32, char, String)) {
928 let json = JsonValue::Array(
929 vec![
930 JsonValue::Number(Number::from(value.0)),
931 JsonValue::Number(Number::from(value.1 as u32)),
932 JsonValue::String(value.2.clone()),
933 ]);
934 let result = validate_function_parameter(&json, &tuple(vec![
935 s32(),
936 chr(),
937 str(),
938 ]));
939 prop_assert_eq!(result, Ok(Value::Tuple(
940 vec![
941 Value::S32(value.0),
942 Value::Char(value.1),
943 Value::String(value.2),
944 ])));
945 }
946
947 #[test]
948 fn test_record_bool_fields_param(value in
949 any::<Vec<(String, bool)>>().prop_filter("Keys are distinct", |pairs|
950 pairs.iter().map(|(k, _)| k).collect::<HashSet<_>>().len() == pairs.len())
951 ) {
952 let json = JsonValue::Object(
953 value.iter().map(|(k, v)| (k.clone(), JsonValue::Bool(*v))).collect());
954 let result = validate_function_parameter(&json, &record(
955 value.iter().map(|(k, _)| field(k, bool())).collect()
956 ));
957 prop_assert_eq!(result, Ok(Value::Record(
958 value.iter().map(|(_, v)| Value::Bool(*v)).collect())));
959 }
960
961 #[test]
962 fn test_flags_param(value in
963 any::<Vec<(String, bool)>>().prop_filter("Keys are distinct", |pairs|
964 pairs.iter().map(|(k, _)| k).collect::<HashSet<_>>().len() == pairs.len())
965 ) {
966 let enabled: Vec<String> = value.iter().filter(|(_, v)| *v).map(|(k, _)| k.clone()).collect();
967 let json = JsonValue::Array(enabled.iter().map(|v| JsonValue::String(v.clone())).collect());
968 let result = validate_function_parameter(&json, &flags(&value.iter().map(|(k, _)| k.as_str()).collect::<Vec<&str>>()));
969 prop_assert_eq!(result, Ok(Value::Flags(
970 value.iter().map(|(_, v)| *v).collect())
971 ));
972 }
973
974 #[test]
975 fn test_enum_param((names, idx) in (any::<HashSet<String>>().prop_filter("Name list is non empty", |names| !names.is_empty()), any::<usize>())) {
976 let names: Vec<String> = names.into_iter().collect();
977 let idx = idx % names.len();
978 let json = JsonValue::String(names[idx].clone());
979 let result = validate_function_parameter(&json, &r#enum(&names.iter().map(|s| s.as_str()).collect::<Vec<&str>>()));
980 prop_assert_eq!(result, Ok(Value::Enum(idx as u32)));
981 }
982
983 #[test]
984 fn test_option_string_param(value: Option<String>) {
985 let json = match &value {
986 Some(v) => JsonValue::String(v.clone()),
987 None => JsonValue::Null,
988 };
989 let result = validate_function_parameter(&json, &option(str()));
990 prop_assert_eq!(result, Ok(Value::Option(value.map(|v| Box::new(Value::String(v))))));
991 }
992
993 #[test]
994 fn test_result_option_s32_string_param(value: Result<Option<i32>, String>) {
995 let json = match &value {
996 Ok(None) => JsonValue::Object(vec![("ok".to_string(), JsonValue::Null)].into_iter().collect()),
997 Ok(Some(v)) => JsonValue::Object(vec![("ok".to_string(), JsonValue::Number(Number::from(*v)))].into_iter().collect()),
998 Err(e) => JsonValue::Object(vec![("err".to_string(), JsonValue::String(e.clone()))].into_iter().collect()),
999 };
1000 let result = validate_function_parameter(&json, &result(option(s32()), str()));
1001 prop_assert_eq!(result, Ok(Value::Result(
1002 match value {
1003 Ok(None) => Ok(Some(Box::new(Value::Option(None)))),
1004 Ok(Some(v)) => Ok(Some(Box::new(Value::Option(Some(Box::new(Value::S32(v))))))),
1005 Err(e) => Err(Some(Box::new(Value::String(e)))),
1006 }
1007 )));
1008 }
1009
1010 #[test]
1011 fn test_variant_u8tuple_string_param(first: (u32, u32), second: String, discriminator in 0i32..1i32) {
1012 let json = match discriminator {
1013 0 => JsonValue::Object(vec![
1014 ("first".to_string(), JsonValue::Array(vec![
1015 JsonValue::Number(Number::from(first.0)),
1016 JsonValue::Number(Number::from(first.1)),
1017 ])),
1018 ].into_iter().collect()),
1019 1 => JsonValue::Object(vec![
1020 ("second".to_string(), JsonValue::String(second.clone())),
1021 ].into_iter().collect()),
1022 _ => panic!("Invalid discriminator value"),
1023 };
1024 let result = validate_function_parameter(&json, &variant(vec![
1025 case("first", tuple(vec![u32(), u32()])),
1026 case("second", str()),
1027 ]));
1028 prop_assert_eq!(result, Ok(Value::Variant {
1029 case_idx: discriminator as u32,
1030 case_value: match discriminator {
1031 0 => Some(Box::new(Value::Tuple(vec![Value::U32(first.0), Value::U32(first.1)]))),
1032 1 => Some(Box::new(Value::String(second))),
1033 _ => panic!("Invalid discriminator value"),
1034 }
1035 }));
1036 }
1037
1038 #[test]
1039 fn test_u8_result(value: u8) {
1040 let result = Value::U8(value);
1041 let expected_type = u8();
1042 let json = validate_function_result(result, &expected_type);
1043 prop_assert_eq!(json, Ok(JsonValue::Number(Number::from(value))));
1044 }
1045
1046 #[test]
1047 fn test_u16_result(value: u16) {
1048 let result = Value::U16(value);
1049 let expected_type = u16();
1050 let json = validate_function_result(result, &expected_type);
1051 prop_assert_eq!(json, Ok(JsonValue::Number(Number::from(value))));
1052 }
1053
1054 #[test]
1055 fn test_u32_result(value: u32) {
1056 let result = Value::U32(value);
1057 let expected_type = u32();
1058 let json = validate_function_result(result, &expected_type);
1059 prop_assert_eq!(json, Ok(JsonValue::Number(Number::from(value))));
1060 }
1061
1062 #[test]
1063 fn test_u64_result(value: u64) {
1064 let result = Value::U64(value);
1065 let expected_type = u64();
1066 let json = validate_function_result(result, &expected_type);
1067 prop_assert_eq!(json, Ok(JsonValue::Number(Number::from(value))));
1068 }
1069
1070 #[test]
1071 fn test_s8_result(value: i8) {
1072 let result = Value::S8(value);
1073 let expected_type = s8();
1074 let json = validate_function_result(result, &expected_type);
1075 prop_assert_eq!(json, Ok(JsonValue::Number(Number::from(value))));
1076 }
1077
1078 #[test]
1079 fn test_s16_result(value: i16) {
1080 let result = Value::S16(value);
1081 let expected_type = s16();
1082 let json = validate_function_result(result, &expected_type);
1083 prop_assert_eq!(json, Ok(JsonValue::Number(Number::from(value))));
1084 }
1085
1086 #[test]
1087 fn test_s32_result(value: i32) {
1088 let result = Value::S32(value);
1089 let expected_type = s32();
1090 let json = validate_function_result(result, &expected_type);
1091 prop_assert_eq!(json, Ok(JsonValue::Number(Number::from(value))));
1092 }
1093
1094 #[test]
1095 fn test_s64_result(value: i64) {
1096 let result = Value::S64(value);
1097 let expected_type = s64();
1098 let json = validate_function_result(result, &expected_type);
1099 prop_assert_eq!(json, Ok(JsonValue::Number(Number::from(value))));
1100 }
1101
1102 #[test]
1103 fn test_f32_result(value: f32) {
1104 let result = Value::F32(value);
1105 let expected_type = f32();
1106 let json = validate_function_result(result, &expected_type);
1107 prop_assert_eq!(json, Ok(JsonValue::Number(Number::from_f64(value as f64).unwrap())));
1108 }
1109
1110 #[test]
1111 fn test_f64_result(value: f64) {
1112 let result = Value::F64(value);
1113 let expected_type = f64();
1114 let json = validate_function_result(result, &expected_type);
1115 prop_assert_eq!(json, Ok(JsonValue::Number(Number::from_f64(value).unwrap())));
1116 }
1117
1118 #[test]
1119 fn test_char_result(value: char) {
1120 let result = Value::Char(value);
1121 let expected_type = chr();
1122 let json = validate_function_result(result, &expected_type);
1123 prop_assert_eq!(json, Ok(JsonValue::Number(Number::from(value as u32))));
1124 }
1125
1126 #[test]
1127 fn test_string_result(value: String) {
1128 let result = Value::String(value.clone());
1129 let expected_type = str();
1130 let json = validate_function_result(result, &expected_type);
1131 prop_assert_eq!(json, Ok(JsonValue::String(value)));
1132 }
1133
1134 #[test]
1135 fn test_list_i32_result(value: Vec<i32>) {
1136 let result = Value::List(value.iter().map(|v| Value::S32(*v)).collect());
1137 let expected_type = list(s32());
1138 let json = validate_function_result(result, &expected_type);
1139 prop_assert_eq!(json, Ok(JsonValue::Array(value.into_iter().map(|v| JsonValue::Number(Number::from(v))).collect())));
1140 }
1141
1142 #[test]
1143 fn test_tuple_string_bool_result(value: (String, bool)) {
1144 let result = Value::Tuple(vec![Value::String(value.0.clone()), Value::Bool(value.1)]);
1145 let expected_type = tuple(vec![str(), bool()]);
1146 let json = validate_function_result(result, &expected_type);
1147 prop_assert_eq!(json, Ok(JsonValue::Array(vec![JsonValue::String(value.0), JsonValue::Bool(value.1)])));
1148 }
1149
1150 #[test]
1151 fn test_record_list_u8_fields(value in any::<Vec<(String, Vec<u8>)>>().prop_filter("Keys are distinct", |pairs|
1152 pairs.iter().map(|(k, _)| k).collect::<HashSet<_>>().len() == pairs.len())
1153 ) {
1154 let result = Value::Record(
1155 value.iter().map(|(_, v)| Value::List(v.iter().map(|n| Value::U8(*n)).collect())).collect());
1156 let expected_type = record(
1157 value.iter().map(|(k, _)| field(k, list(u8()))).collect()
1158 );
1159 let json = validate_function_result(result, &expected_type);
1160 let expected_json = JsonValue::Object(
1161 value.iter().map(|(k, v)| (k.clone(), JsonValue::Array(v.iter().map(|n| JsonValue::Number(Number::from(*n))).collect()))).collect());
1162 prop_assert_eq!(json, Ok(expected_json));
1163 }
1164
1165 #[test]
1166 fn test_flags_result(pairs in
1167 any::<Vec<(String, bool)>>().prop_filter("Keys are distinct", |pairs|
1168 pairs.iter().map(|(k, _)| k).collect::<HashSet<_>>().len() == pairs.len())
1169 ) {
1170 let enabled: Vec<String> = pairs.iter().filter(|(_, v)| *v).map(|(k, _)| k.clone()).collect();
1171 let value = Value::Flags(pairs.iter().map(|(_, v)| *v).collect());
1172 let result = validate_function_result(value, &flags(&pairs.iter().map(|(k, _)| k.as_str()).collect::<Vec<&str>>()));
1173 prop_assert_eq!(result, Ok(
1174 JsonValue::Array(enabled.iter().map(|v| JsonValue::String(v.clone())).collect())
1175 ));
1176 }
1177
1178 #[test]
1179 fn test_enum_result((names, idx) in (any::<HashSet<String>>().prop_filter("Name list is non empty", |names| !names.is_empty()), any::<usize>())) {
1180 let names: Vec<String> = names.into_iter().collect();
1181 let idx = idx % names.len();
1182 let value = Value::Enum(idx as u32);
1183 let result = validate_function_result(value, &r#enum(&names.iter().map(|s| s.as_str()).collect::<Vec<&str>>()));
1184 prop_assert_eq!(result, Ok(JsonValue::String(names[idx].clone())));
1185 }
1186
1187 #[test]
1188 fn test_option_string_result(opt: Option<String>) {
1189 let value = Value::Option(opt.clone().map(|v| Box::new(Value::String(v))));
1190 let result = validate_function_result(value, &option(str()));
1191 let json = match opt {
1192 Some(str) => Ok(JsonValue::String(str)),
1193 None => Ok(JsonValue::Null),
1194 };
1195 prop_assert_eq!(result, json);
1196 }
1197
1198 #[test]
1199 fn test_variant_u8tuple_string_result(first: (u32, u32), second: String, discriminator in 0i32..1i32) {
1200 let value = Value::Variant {
1201 case_idx: discriminator as u32,
1202 case_value: match discriminator {
1203 0 => Some(Box::new(Value::Tuple(vec![Value::U32(first.0), Value::U32(first.1)]))),
1204 1 => Some(Box::new(Value::String(second.clone()))),
1205 _ => panic!("Invalid discriminator value"),
1206 }
1207 };
1208 let result = validate_function_result(value, &variant(vec![
1209 case("first", tuple(vec![u32(), u32()])),
1210 case("second", str()),
1211 ]));
1212 let json = match discriminator {
1213 0 => JsonValue::Object(vec![
1214 ("first".to_string(), JsonValue::Array(vec![
1215 JsonValue::Number(Number::from(first.0)),
1216 JsonValue::Number(Number::from(first.1)),
1217 ])),
1218 ].into_iter().collect()),
1219 1 => JsonValue::Object(vec![
1220 ("second".to_string(), JsonValue::String(second)),
1221 ].into_iter().collect()),
1222 _ => panic!("Invalid discriminator value"),
1223 };
1224 prop_assert_eq!(result, Ok(json));
1225 }
1226 }
1227
1228 #[test]
1229 fn json_null_works_as_none() {
1230 let json = JsonValue::Null;
1231 let result = validate_function_parameter(&json, &option(str()));
1232 assert_eq!(result, Ok(Value::Option(None)));
1233 }
1234
1235 #[test]
1236 fn missing_field_works_as_none() {
1237 let json = JsonValue::Object(
1238 vec![("x".to_string(), JsonValue::String("a".to_string()))]
1239 .into_iter()
1240 .collect(),
1241 );
1242 let result = validate_function_parameter(
1243 &json,
1244 &record(vec![field("x", str()), field("y", option(str()))]),
1245 );
1246 assert_eq!(
1247 result,
1248 Ok(Value::Record(vec![
1249 Value::String("a".to_string()),
1250 Value::Option(None),
1251 ]))
1252 );
1253 }
1254}