fn from_dict, heap: &'v Heap) -> anyhow::Result()

in starlark/src/values/typing.rs [175:224]


    fn from_dict<'v>(t: DictRef<'v>, heap: &'v Heap) -> anyhow::Result<TypeCompiled> {
        // Dictionary with a single element
        fn unpack_singleton_dictionary<'v>(x: &Dict<'v>) -> Option<(Value<'v>, Value<'v>)> {
            if x.len() == 1 { x.iter().next() } else { None }
        }

        if t.is_empty() {
            Ok(TypeCompiled::is_dict())
        } else if let Some((tk, tv)) = unpack_singleton_dictionary(&t) {
            // Dict of the form {k: v} must all match the k/v types
            let tk = TypeCompiled::new(tk, heap)?;
            let tv = TypeCompiled::new(tv, heap)?;
            Ok(TypeCompiled::is_dict_of(tk, tv))
        } else {
            // Dict type, allowed to have more keys that aren't used.
            // All specified must be type String.
            let ts = t
                .iter_hashed()
                .map(|(k, kt)| {
                    let k_str = match k.key().unpack_str() {
                        None => {
                            return Err(TypingError::InvalidTypeAnnotation(t.to_string()).into());
                        }
                        Some(s) => Hashed::new_unchecked(k.hash(), s.to_owned()),
                    };
                    let kt = TypeCompiled::new(kt, heap)?;
                    Ok((k_str, kt))
                })
                .collect::<anyhow::Result<Vec<_>>>()?;

            Ok(TypeCompiled(box move |v| match Dict::from_value(v) {
                None => false,
                Some(v) => {
                    for (k, kt) in &ts {
                        let ks = k.key().as_str();
                        let ks = Hashed::new_unchecked(k.hash(), ks);
                        match v.get_str_hashed(ks) {
                            None => return false,
                            Some(kv) => {
                                if !(kt.0)(kv) {
                                    return false;
                                }
                            }
                        }
                    }
                    true
                }
            }))
        }
    }