compris/hints/
conversion.rs

1use super::{
2    super::{annotate::*, normal::*, parse::*},
3    hints::*,
4};
5
6use kutil::std::immutable::*;
7
8impl<AnnotatedT> Variant<AnnotatedT> {
9    /// Attempts to convert the [Variant] to a hinted [Variant].
10    ///
11    /// Also converts escaped hints to their unescaped values.
12    pub fn to_hinted_variant(&self, hints: &Hints) -> Result<Option<Variant<AnnotatedT>>, ParseError>
13    where
14        AnnotatedT: Annotated + Clone + Default,
15    {
16        if let Some((key, value)) = self.to_key_value_pair()
17            && let Variant::Text(hint) = key
18        {
19            if hint.inner == hints.integer {
20                let text = value.validate_hinted_text(&hints.integer)?;
21                let integer: i64 = text.inner.parse()?;
22                tracing::trace!("hinted {}: {}", hints.integer, integer);
23                return Ok(Some(Integer::from(integer).with_annotations_from(text).into()));
24            } else if hint.inner == hints.unsigned_integer {
25                let text = value.validate_hinted_text(&hints.unsigned_integer)?;
26                let unsigned_integer: u64 = text.inner.parse()?;
27                tracing::trace!("hinted {}: {}", hints.unsigned_integer, unsigned_integer);
28                return Ok(Some(UnsignedInteger::from(unsigned_integer).with_annotations_from(text).into()));
29            } else if hint.inner == hints.bytes {
30                let text = value.validate_hinted_text(&hints.bytes)?;
31                let blob = Blob::new_from_base64(&text.inner)?;
32                tracing::trace!("hinted {}: {} bytes", hints.bytes, blob.inner.len());
33                return Ok(Some(blob.with_annotations_from(text).into()));
34            } else if hint.inner == hints.map {
35                let list = value.validate_hinted_list(&hints.map)?;
36                let mut new_map = Map::default();
37
38                for item in list {
39                    let entry = item.validate_hinted_list(&hints.map)?;
40                    if let Some((key, value)) = entry.to_pair() {
41                        let key = if let Some(hinted) = key.to_hinted_variant(hints)? { hinted } else { key.clone() };
42
43                        let value =
44                            if let Some(hinted) = value.to_hinted_variant(hints)? { hinted } else { value.clone() };
45
46                        new_map.inner.insert(key, value);
47
48                        // Note: we will allow duplicate keys above, because JSON does, too
49                        // if new_map.value.insert(key, value).is_some() {
50                        //     return Err(ReadError::Hint(format!("malformed {:?}, duplicate key", hints.map)));
51                        // }
52                    } else {
53                        return Err(ParseError::Hint(format!("malformed {:?}, item length is not 2", hints.map)));
54                    }
55                }
56
57                tracing::trace!("hinted {}: {}", hints.map, new_map.inner.len());
58                return Ok(Some(new_map.with_annotations_from(list).into()));
59            } else if hint.inner == hints.escaped_integer {
60                tracing::trace!("escaped hint: {}", hints.integer);
61                return Ok(Some(self.unescape_hint(&hints.integer, key, value)));
62            } else if hint.inner == hints.escaped_unsigned_integer {
63                tracing::trace!("escaped hint: {}", hints.unsigned_integer);
64                return Ok(Some(self.unescape_hint(&hints.unsigned_integer, key, value)));
65            } else if hint.inner == hints.escaped_bytes {
66                tracing::trace!("escaped hint: {}", hints.bytes);
67                return Ok(Some(self.unescape_hint(&hints.bytes, key, value)));
68            } else if hint.inner == hints.escaped_map {
69                tracing::trace!("escaped hint: {}", hints.map);
70                return Ok(Some(self.unescape_hint(&hints.map, key, value)));
71            }
72        }
73
74        Ok(None)
75    }
76
77    fn validate_hinted_text(&self, hint: &str) -> Result<&Text<AnnotatedT>, ParseError> {
78        match self {
79            Variant::Text(text) => Ok(text),
80            _ => Err(ParseError::Hint(format!("malformed {:?}, not text", hint))),
81        }
82    }
83
84    fn validate_hinted_list(&self, hint: &str) -> Result<&List<AnnotatedT>, ParseError> {
85        match self {
86            Variant::List(list) => Ok(list),
87            _ => Err(ParseError::Hint(format!("malformed {:?}, not a list", hint))),
88        }
89    }
90
91    fn unescape_hint(&self, new_key: &str, key: &Variant<AnnotatedT>, variant: &Variant<AnnotatedT>) -> Self
92    where
93        AnnotatedT: Annotated + Clone + Default,
94    {
95        let mut new_map = Map::default();
96        new_map.inner.insert(Variant::from(ByteString::from(new_key)).with_annotations_from(key), variant.clone());
97        new_map.with_annotations_from(self).into()
98    }
99}