amadeus_utils/vecpak/
ext.rs1use 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 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 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}