torrust_tracker_contrib_bencode/access/
convert.rs

1#![allow(clippy::missing_errors_doc)]
2use crate::access::bencode::{BRefAccess, BRefAccessExt};
3use crate::access::dict::BDictAccess;
4use crate::access::list::BListAccess;
5use crate::BencodeConvertError;
6
7/// Trait for extended casting of bencode objects and converting conversion errors into application specific errors.
8pub trait BConvertExt: BConvert {
9    /// See `BConvert::convert_bytes`.
10    fn convert_bytes_ext<'a, B, E>(&self, bencode: B, error_key: E) -> Result<&'a [u8], Self::Error>
11    where
12        B: BRefAccessExt<'a>,
13        E: AsRef<[u8]>,
14    {
15        bencode.bytes_ext().ok_or(self.handle_error(BencodeConvertError::WrongType {
16            key: error_key.as_ref().to_owned(),
17            expected_type: "Bytes".to_owned(),
18        }))
19    }
20
21    /// See `BConvert::convert_str`.
22    fn convert_str_ext<'a, B, E>(&self, bencode: &B, error_key: E) -> Result<&'a str, Self::Error>
23    where
24        B: BRefAccessExt<'a>,
25        E: AsRef<[u8]>,
26    {
27        bencode.str_ext().ok_or(self.handle_error(BencodeConvertError::WrongType {
28            key: error_key.as_ref().to_owned(),
29            expected_type: "UTF-8 Bytes".to_owned(),
30        }))
31    }
32
33    /// See `BConvert::lookup_and_convert_bytes`.
34    fn lookup_and_convert_bytes_ext<'a, B, K1, K2>(
35        &self,
36        dictionary: &dyn BDictAccess<K1, B>,
37        key: K2,
38    ) -> Result<&'a [u8], Self::Error>
39    where
40        B: BRefAccessExt<'a>,
41        K2: AsRef<[u8]>,
42    {
43        self.convert_bytes_ext(self.lookup(dictionary, &key)?, &key)
44    }
45
46    /// See `BConvert::lookup_and_convert_str`.
47    fn lookup_and_convert_str_ext<'a, B, K1, K2>(
48        &self,
49        dictionary: &dyn BDictAccess<K1, B>,
50        key: K2,
51    ) -> Result<&'a str, Self::Error>
52    where
53        B: BRefAccessExt<'a>,
54        K2: AsRef<[u8]>,
55    {
56        self.convert_str_ext(self.lookup(dictionary, &key)?, &key)
57    }
58}
59
60/// Trait for casting bencode objects and converting conversion errors into application specific errors.
61#[allow(clippy::module_name_repetitions)]
62pub trait BConvert {
63    type Error;
64
65    /// Convert the given conversion error into the appropriate error type.
66    fn handle_error(&self, error: BencodeConvertError) -> Self::Error;
67
68    /// Attempt to convert the given bencode value into an integer.
69    ///
70    /// Error key is used to generate an appropriate error message should the operation return an error.
71    fn convert_int<B, E>(&self, bencode: B, error_key: E) -> Result<i64, Self::Error>
72    where
73        B: BRefAccess,
74        E: AsRef<[u8]>,
75    {
76        bencode.int().ok_or(self.handle_error(BencodeConvertError::WrongType {
77            key: error_key.as_ref().to_owned(),
78            expected_type: "Integer".to_owned(),
79        }))
80    }
81
82    /// Attempt to convert the given bencode value into bytes.
83    ///
84    /// Error key is used to generate an appropriate error message should the operation return an error.
85    fn convert_bytes<'a, B, E>(&self, bencode: &'a B, error_key: E) -> Result<&'a [u8], Self::Error>
86    where
87        B: BRefAccess,
88        E: AsRef<[u8]>,
89    {
90        bencode.bytes().ok_or(self.handle_error(BencodeConvertError::WrongType {
91            key: error_key.as_ref().to_owned(),
92            expected_type: "Bytes".to_owned(),
93        }))
94    }
95
96    /// Attempt to convert the given bencode value into a UTF-8 string.
97    ///
98    /// Error key is used to generate an appropriate error message should the operation return an error.
99    fn convert_str<'a, B, E>(&self, bencode: &'a B, error_key: E) -> Result<&'a str, Self::Error>
100    where
101        B: BRefAccess,
102        E: AsRef<[u8]>,
103    {
104        bencode.str().ok_or(self.handle_error(BencodeConvertError::WrongType {
105            key: error_key.as_ref().to_owned(),
106            expected_type: "UTF-8 Bytes".to_owned(),
107        }))
108    }
109
110    /// Attempt to convert the given bencode value into a list.
111    ///
112    /// Error key is used to generate an appropriate error message should the operation return an error.
113    fn convert_list<'a, B, E>(&self, bencode: &'a B, error_key: E) -> Result<&'a dyn BListAccess<B::BType>, Self::Error>
114    where
115        B: BRefAccess,
116        E: AsRef<[u8]>,
117    {
118        bencode.list().ok_or(self.handle_error(BencodeConvertError::WrongType {
119            key: error_key.as_ref().to_owned(),
120            expected_type: "List".to_owned(),
121        }))
122    }
123
124    /// Attempt to convert the given bencode value into a dictionary.
125    ///
126    /// Error key is used to generate an appropriate error message should the operation return an error.
127    fn convert_dict<'a, B, E>(&self, bencode: &'a B, error_key: E) -> Result<&'a dyn BDictAccess<B::BKey, B::BType>, Self::Error>
128    where
129        B: BRefAccess,
130        E: AsRef<[u8]>,
131    {
132        bencode.dict().ok_or(self.handle_error(BencodeConvertError::WrongType {
133            key: error_key.as_ref().to_owned(),
134            expected_type: "Dictionary".to_owned(),
135        }))
136    }
137
138    /// Look up a value in a dictionary of bencoded values using the given key.
139    fn lookup<'a, B, K1, K2>(&self, dictionary: &'a dyn BDictAccess<K1, B>, key: K2) -> Result<&'a B, Self::Error>
140    where
141        B: BRefAccess,
142        K2: AsRef<[u8]>,
143    {
144        let key_ref = key.as_ref();
145
146        match dictionary.lookup(key_ref) {
147            Some(n) => Ok(n),
148            None => Err(self.handle_error(BencodeConvertError::MissingKey { key: key_ref.to_owned() })),
149        }
150    }
151
152    /// Combines a lookup operation on the given key with a conversion of the value, if found, to an integer.
153    fn lookup_and_convert_int<B, K1, K2>(&self, dictionary: &dyn BDictAccess<K1, B>, key: K2) -> Result<i64, Self::Error>
154    where
155        B: BRefAccess,
156        K2: AsRef<[u8]>,
157    {
158        self.convert_int(self.lookup(dictionary, &key)?, &key)
159    }
160
161    /// Combines a lookup operation on the given key with a conversion of the value, if found, to a series of bytes.
162    fn lookup_and_convert_bytes<'a, B, K1, K2>(
163        &self,
164        dictionary: &'a dyn BDictAccess<K1, B>,
165        key: K2,
166    ) -> Result<&'a [u8], Self::Error>
167    where
168        B: BRefAccess,
169        K2: AsRef<[u8]>,
170    {
171        self.convert_bytes(self.lookup(dictionary, &key)?, &key)
172    }
173
174    /// Combines a lookup operation on the given key with a conversion of the value, if found, to a UTF-8 string.
175    fn lookup_and_convert_str<'a, B, K1, K2>(
176        &self,
177        dictionary: &'a dyn BDictAccess<K1, B>,
178        key: K2,
179    ) -> Result<&'a str, Self::Error>
180    where
181        B: BRefAccess,
182        K2: AsRef<[u8]>,
183    {
184        self.convert_str(self.lookup(dictionary, &key)?, &key)
185    }
186
187    /// Combines a lookup operation on the given key with a conversion of the value, if found, to a list.
188    fn lookup_and_convert_list<'a, B, K1, K2>(
189        &self,
190        dictionary: &'a dyn BDictAccess<K1, B>,
191        key: K2,
192    ) -> Result<&'a dyn BListAccess<B::BType>, Self::Error>
193    where
194        B: BRefAccess,
195        K2: AsRef<[u8]>,
196    {
197        self.convert_list(self.lookup(dictionary, &key)?, &key)
198    }
199
200    /// Combines a lookup operation on the given key with a conversion of the value, if found, to a dictionary.
201    fn lookup_and_convert_dict<'a, B, K1, K2>(
202        &self,
203        dictionary: &'a dyn BDictAccess<K1, B>,
204        key: K2,
205    ) -> Result<&'a dyn BDictAccess<B::BKey, B::BType>, Self::Error>
206    where
207        B: BRefAccess,
208        K2: AsRef<[u8]>,
209    {
210        self.convert_dict(self.lookup(dictionary, &key)?, &key)
211    }
212}