1use serde_json::Value;
2use std::collections::HashMap;
3
4use crate::error::{value_type_name, IssueCode, PathSegment, VldError};
5use crate::schema::VldSchema;
6
7pub struct ZMap<K: VldSchema, V: VldSchema> {
18 key_schema: K,
19 value_schema: V,
20}
21
22impl<K: VldSchema, V: VldSchema> ZMap<K, V> {
23 pub fn new(key_schema: K, value_schema: V) -> Self {
24 Self {
25 key_schema,
26 value_schema,
27 }
28 }
29}
30
31impl<K, V> VldSchema for ZMap<K, V>
32where
33 K: VldSchema,
34 V: VldSchema,
35 K::Output: Eq + std::hash::Hash,
36{
37 type Output = HashMap<K::Output, V::Output>;
38
39 fn parse_value(&self, value: &Value) -> Result<Self::Output, VldError> {
40 let arr = value.as_array().ok_or_else(|| {
41 VldError::single(
42 IssueCode::InvalidType {
43 expected: "array".to_string(),
44 received: value_type_name(value),
45 },
46 format!(
47 "Expected array of [key, value] pairs, received {}",
48 value_type_name(value)
49 ),
50 )
51 })?;
52
53 let mut result = HashMap::new();
54 let mut errors = VldError::new();
55
56 for (i, item) in arr.iter().enumerate() {
57 let pair = item.as_array().filter(|a| a.len() == 2);
58 match pair {
59 Some(pair) => {
60 let k = match self.key_schema.parse_value(&pair[0]) {
61 Ok(k) => Some(k),
62 Err(e) => {
63 errors = errors.merge(e.with_prefix(PathSegment::Index(i)));
64 None
65 }
66 };
67 let v = match self.value_schema.parse_value(&pair[1]) {
68 Ok(v) => Some(v),
69 Err(e) => {
70 errors = errors.merge(e.with_prefix(PathSegment::Index(i)));
71 None
72 }
73 };
74 if let (Some(k), Some(v)) = (k, v) {
75 result.insert(k, v);
76 }
77 }
78 None => {
79 let mut e = VldError::single(
80 IssueCode::Custom {
81 code: "invalid_map_entry".to_string(),
82 },
83 "Each Map entry must be a [key, value] array of length 2",
84 );
85 e = e.with_prefix(PathSegment::Index(i));
86 errors = errors.merge(e);
87 }
88 }
89 }
90
91 if errors.is_empty() {
92 Ok(result)
93 } else {
94 Err(errors)
95 }
96 }
97}