fn validate_types()

in components/support/nimbus-fml/src/defaults/validator.rs [239:345]


    fn validate_types(
        &self,
        path: &ErrorPath,
        type_ref: &TypeRef,
        default: &Value,
        errors: &mut Vec<FeatureValidationError>,
    ) {
        match (type_ref, default) {
            (TypeRef::Boolean, Value::Bool(_))
            | (TypeRef::BundleImage, Value::String(_))
            | (TypeRef::BundleText, Value::String(_))
            | (TypeRef::String, Value::String(_))
            | (TypeRef::StringAlias(_), Value::String(_))
            | (TypeRef::Int, Value::Number(_))
            | (TypeRef::Option(_), Value::Null) => (),
            (TypeRef::Option(inner), v) => {
                self.validate_types(path, inner, v, errors)
            }
            (TypeRef::Enum(enum_name), Value::String(s)) => {
                let enum_def = self
                    .get_enum(enum_name)
                    // If this is thrown, there's a problem in validate_type_ref.
                    .unwrap_or_else(|| {
                        unreachable!("Enum {enum_name} is not defined in the manifest")
                    });
                let mut valid = HashSet::new();
                for variant in enum_def.variants() {
                    let name = variant.name();
                    if *s == name {
                        return;
                    }
                    valid.insert(name);
                }
                let path = path.final_error_quoted(s);
                errors.push(FeatureValidationError {
                    path,
                    kind: ErrorKind::invalid_value(type_ref),
                });
            }
            (TypeRef::EnumMap(enum_type, map_type), Value::Object(map))
                if matches!(**enum_type, TypeRef::Enum(_)) =>
            {
                let enum_name = enum_type.name().unwrap();
                let enum_def = self
                    .get_enum(enum_name)
                    // If this is thrown, there's a problem in validate_type_ref.
                    .unwrap_or_else(|| {
                        unreachable!("Enum {enum_name} is not defined in the manifest")
                    });

                // We first validate that the keys of the map cover all all the enum variants, and no more or less
                let mut valid = HashSet::new();
                for variant in &enum_def.variants {
                    let nm = &variant.name;
                    valid.insert(nm.clone());

                    let map_value = map.get(nm);
                    match (map_type.as_ref(), map_value) {
                        (TypeRef::Option(_), None) => (),
                        (_, Some(inner)) => {
                            self.validate_types(&path.enum_map_key(enum_name, nm), map_type, inner, errors);
                        }
                        _ => ()
                    }
                }

                for (map_key, map_value) in map {
                    if !valid.contains(map_key) {
                        let path = path.map_key(map_key);
                        errors.push(FeatureValidationError {
                            path,
                            kind: ErrorKind::invalid_key(enum_type, map),
                        });
                    }

                    self.validate_types(&path.enum_map_key(&enum_def.name, map_key), map_type, map_value, errors);
                }
            }
            (TypeRef::EnumMap(_, map_type), Value::Object(map)) // Map<string-alias, T>
            | (TypeRef::StringMap(map_type), Value::Object(map)) => {
                for (key, value) in map {
                    self.validate_types(&path.map_key(key), map_type, value, errors);
                }
            }
            (TypeRef::List(list_type), Value::Array(arr)) => {
                for (index, value) in arr.iter().enumerate() {
                    self.validate_types(&path.array_index(index), list_type, value, errors);
                }
            }
            (TypeRef::Object(obj_name), Value::Object(map)) => {
                let obj_def = self
                    .get_object(obj_name)
                    // If this is thrown, there's a problem in validate_type_ref.
                    .unwrap_or_else(|| {
                        unreachable!("Object {obj_name} is not defined in the manifest")
                    });
                self.validate_props_types(&path.object_value(obj_name), &obj_def.props, map, errors);
            }
            _ => {
                let path = path.final_error_value(default);
                errors.push(FeatureValidationError {
                    path,
                    kind: ErrorKind::type_mismatch(type_ref),
                });
            }
        };
    }