Skip to main content

interstice_abi/interstice_value/
validate.rs

1use std::collections::HashMap;
2
3use crate::{IntersticeType, IntersticeTypeDef, IntersticeValue};
4
5pub fn validate_value(
6    value: &IntersticeValue,
7    ty: &IntersticeType,
8    type_definitions: &HashMap<String, IntersticeTypeDef>,
9) -> bool {
10    validate_value_detailed(value, ty, type_definitions).is_ok()
11}
12
13pub fn validate_value_detailed(
14    value: &IntersticeValue,
15    ty: &IntersticeType,
16    type_definitions: &HashMap<String, IntersticeTypeDef>,
17) -> Result<(), String> {
18    match value {
19        IntersticeValue::Void => {
20            if let IntersticeType::Void = ty { Ok(()) } else { Err(format!("expected Void, got {:?}", ty)) }
21        }
22        IntersticeValue::Bool(_) => {
23            if let IntersticeType::Bool = ty { Ok(()) } else { Err(format!("expected Bool, got {:?}", ty)) }
24        }
25        IntersticeValue::U32(_) => {
26            if let IntersticeType::U32 = ty { Ok(()) } else { Err(format!("expected U32, got {:?}", ty)) }
27        }
28        IntersticeValue::U8(_) => {
29            if let IntersticeType::U8 = ty { Ok(()) } else { Err(format!("expected U8, got {:?}", ty)) }
30        }
31        IntersticeValue::U64(_) => {
32            if let IntersticeType::U64 = ty { Ok(()) } else { Err(format!("expected U64, got {:?}", ty)) }
33        }
34        IntersticeValue::I32(_) => {
35            if let IntersticeType::I32 = ty { Ok(()) } else { Err(format!("expected I32, got {:?}", ty)) }
36        }
37        IntersticeValue::I64(_) => {
38            if let IntersticeType::I64 = ty { Ok(()) } else { Err(format!("expected I64, got {:?}", ty)) }
39        }
40        IntersticeValue::F32(_) => {
41            if let IntersticeType::F32 = ty { Ok(()) } else { Err(format!("expected F32, got {:?}", ty)) }
42        }
43        IntersticeValue::F64(_) => {
44            if let IntersticeType::F64 = ty { Ok(()) } else { Err(format!("expected F64, got {:?}", ty)) }
45        }
46        IntersticeValue::String(_) => {
47            if let IntersticeType::String = ty { Ok(()) } else { Err(format!("expected String, got {:?}", ty)) }
48        }
49        IntersticeValue::Vec(v) => {
50            if let IntersticeType::Vec(inner) = ty {
51                for (i, x) in v.iter().enumerate() {
52                    validate_value_detailed(x, inner, type_definitions)
53                        .map_err(|e| format!("Vec[{}]: {}", i, e))?;
54                }
55                Ok(())
56            } else {
57                Err(format!("expected Vec, got {:?}", ty))
58            }
59        }
60        IntersticeValue::Option(None) => {
61            if let IntersticeType::Option(_) = ty { Ok(()) } else { Err(format!("expected Option, got {:?}", ty)) }
62        }
63        IntersticeValue::Option(Some(v)) => {
64            if let IntersticeType::Option(inner) = ty {
65                validate_value_detailed(v, inner, type_definitions)
66                    .map_err(|e| format!("Option<Some>: {}", e))
67            } else {
68                Err(format!("expected Option, got {:?}", ty))
69            }
70        }
71        IntersticeValue::Tuple(interstice_values) => {
72            if let IntersticeType::Tuple(inner) = ty {
73                for (i, (inner_ty, inner_val)) in inner.iter().zip(interstice_values).enumerate() {
74                    validate_value_detailed(inner_val, inner_ty, type_definitions)
75                        .map_err(|e| format!("Tuple[{}]: {}", i, e))?;
76                }
77                Ok(())
78            } else {
79                Err(format!("expected Tuple, got {:?}", ty))
80            }
81        }
82        IntersticeValue::Struct { name, fields } => {
83            if let IntersticeType::Named(type_name) = ty {
84                if type_name != name {
85                    return Err(format!("struct name mismatch: expected '{}', got '{}'", type_name, name));
86                }
87                if let Some(IntersticeTypeDef::Struct {
88                    name: _name_def,
89                    fields: fields_def,
90                }) = type_definitions.get(type_name)
91                {
92                    // TODO: here the order of the field definition matter, make it not
93                    for (field, field_def) in fields.iter().zip(fields_def) {
94                        if field.name != field_def.name {
95                            return Err(format!(
96                                "struct '{}' field name mismatch: expected '{}', got '{}'",
97                                type_name, field_def.name, field.name
98                            ));
99                        }
100                        validate_value_detailed(&field.value, &field_def.field_type, type_definitions)
101                            .map_err(|e| format!("struct '{}' field '{}': {}", type_name, field.name, e))?;
102                    }
103                    Ok(())
104                } else {
105                    Err(format!(
106                        "type '{}' not found in type_definitions (available: [{}])",
107                        type_name,
108                        type_definitions.keys().cloned().collect::<Vec<_>>().join(", ")
109                    ))
110                }
111            } else {
112                Err(format!("expected Named type for struct '{}', got {:?}", name, ty))
113            }
114        }
115        IntersticeValue::Enum {
116            name,
117            variant,
118            value,
119        } => {
120            if let IntersticeType::Named(type_name) = ty {
121                if type_name != name {
122                    return Err(format!("enum name mismatch: expected '{}', got '{}'", type_name, name));
123                }
124                if let Some(IntersticeTypeDef::Enum {
125                    name: _name_def,
126                    variants,
127                }) = type_definitions.get(type_name)
128                {
129                    for variant_def in variants {
130                        if &variant_def.name == variant {
131                            return validate_value_detailed(
132                                value,
133                                &variant_def.field_type,
134                                type_definitions,
135                            )
136                            .map_err(|e| format!("enum '{}' variant '{}': {}", type_name, variant, e));
137                        }
138                    }
139                    Err(format!("enum '{}' has no variant '{}'", type_name, variant))
140                } else {
141                    Err(format!(
142                        "type '{}' not found in type_definitions (available: [{}])",
143                        type_name,
144                        type_definitions.keys().cloned().collect::<Vec<_>>().join(", ")
145                    ))
146                }
147            } else {
148                Err(format!("expected Named type for enum '{}', got {:?}", name, ty))
149            }
150        }
151    }
152}