golem_wasm/json/
impl.rs

1// Copyright 2024-2025 Golem Cloud
2//
3// Licensed under the Golem Source License v1.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://license.golem.cloud/LICENSE
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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        // If the JSON value is a string, return it
362        Ok(str_value.to_string().into_value_and_type())
363    } else {
364        // If the JSON value is not a string, return an error with type information
365        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            // not assuming much about the url format, just checking it ends with a /<resource-id-u64>
697            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}