amadeus_utils/vecpak/
ext.rs

1//! Vecpak term utilities similar to eetf TermExt
2
3use super::Term;
4use std::collections::HashMap;
5use tracing::warn;
6
7pub trait VecpakExt {
8    fn get_varint(&self) -> Option<i128>;
9    fn get_binary(&self) -> Option<&[u8]>;
10    fn get_list(&self) -> Option<&[Term]>;
11    fn get_string(&self) -> Option<String>;
12    fn get_proplist_map(&self) -> Option<PropListMap>;
13    fn parse_list<T, E>(&self, parser: impl Fn(&[u8]) -> Result<T, E>) -> Vec<T>
14    where
15        E: std::fmt::Display;
16}
17
18impl VecpakExt for Term {
19    fn get_varint(&self) -> Option<i128> {
20        match self {
21            Term::VarInt(v) => Some(*v),
22            _ => None,
23        }
24    }
25
26    fn get_binary(&self) -> Option<&[u8]> {
27        match self {
28            Term::Binary(bytes) => Some(bytes.as_slice()),
29            _ => None,
30        }
31    }
32
33    fn get_list(&self) -> Option<&[Term]> {
34        match self {
35            Term::List(items) => Some(items.as_slice()),
36            _ => None,
37        }
38    }
39
40    fn get_string(&self) -> Option<String> {
41        self.get_binary().and_then(|b| std::str::from_utf8(b).ok().map(|s| s.to_owned()))
42    }
43
44    fn get_proplist_map(&self) -> Option<PropListMap> {
45        match self {
46            Term::PropList(pairs) => Some(PropListMap(pairs.clone())),
47            _ => None,
48        }
49    }
50
51    fn parse_list<T, E>(&self, parser: impl Fn(&[u8]) -> Result<T, E>) -> Vec<T>
52    where
53        E: std::fmt::Display,
54    {
55        self.get_list().map(|list| parse_list(list, parser)).unwrap_or_default()
56    }
57}
58
59#[derive(Default, Clone, Debug)]
60pub struct PropListMap(pub Vec<(Term, Term)>);
61
62impl PropListMap {
63    pub fn get_by_key(&self, key: &[u8]) -> Option<&Term> {
64        self.0.iter().find_map(|(k, v)| k.get_binary().filter(|&b| b == key).map(|_| v))
65    }
66
67    pub fn get_binary<'a, A>(&'a self, key: &[u8]) -> Option<A>
68    where
69        A: TryFrom<&'a [u8]>,
70    {
71        self.get_by_key(key).and_then(VecpakExt::get_binary).and_then(|b| A::try_from(b).ok())
72    }
73
74    pub fn get_varint<I>(&self, key: &[u8]) -> Option<I>
75    where
76        I: TryFrom<i128>,
77    {
78        self.get_by_key(key).and_then(VecpakExt::get_varint).and_then(|v| I::try_from(v).ok())
79    }
80
81    /// Alias for get_varint for consistency with old TermMap API
82    pub fn get_integer<I>(&self, key: &[u8]) -> Option<I>
83    where
84        I: TryFrom<i128>,
85    {
86        self.get_varint(key)
87    }
88
89    pub fn get_list(&self, key: &[u8]) -> Option<&[Term]> {
90        self.get_by_key(key).and_then(VecpakExt::get_list)
91    }
92
93    pub fn get_string(&self, key: &[u8]) -> Option<String> {
94        self.get_by_key(key).and_then(VecpakExt::get_string)
95    }
96
97    /// Get a nested PropListMap from a key
98    pub fn get_proplist_map(&self, key: &[u8]) -> Option<PropListMap> {
99        self.get_by_key(key).and_then(VecpakExt::get_proplist_map)
100    }
101
102    pub fn parse_list<T, E>(&self, key: &[u8], parser: impl Fn(&[u8]) -> Result<T, E>) -> Vec<T>
103    where
104        E: std::fmt::Display,
105    {
106        self.get_by_key(key).map(|term| term.parse_list(parser)).unwrap_or_default()
107    }
108
109    pub fn into_term(self) -> Term {
110        Term::PropList(self.0)
111    }
112
113    pub fn to_map(&self) -> HashMap<Vec<u8>, Term> {
114        self.0.iter().filter_map(|(k, v)| k.get_binary().map(|b| (b.to_vec(), v.clone()))).collect()
115    }
116}
117
118pub fn parse_list<T, E>(list: &[Term], parser: impl Fn(&[u8]) -> Result<T, E>) -> Vec<T>
119where
120    E: std::fmt::Display,
121{
122    list.iter()
123        .filter_map(|term| {
124            term.get_binary().and_then(|bytes| parser(bytes).map_err(|e| warn!("parse failed: {}", e)).ok())
125        })
126        .collect()
127}