torrust_tracker_contrib_bencode/reference/
bencode_ref.rs1use std::collections::BTreeMap;
2use std::str;
3
4use crate::access::bencode::{BRefAccess, BRefAccessExt, RefKind};
5use crate::access::dict::BDictAccess;
6use crate::access::list::BListAccess;
7use crate::error::{BencodeParseError, BencodeParseResult};
8use crate::reference::decode;
9use crate::reference::decode_opt::BDecodeOpt;
10
11#[derive(Debug, Eq, PartialEq, Clone, Hash)]
13pub enum Inner<'a> {
14 Int(i64, &'a [u8]),
16 Bytes(&'a [u8], &'a [u8]),
18 List(Vec<BencodeRef<'a>>, &'a [u8]),
20 Dict(BTreeMap<&'a [u8], BencodeRef<'a>>, &'a [u8]),
22}
23
24impl<'a> From<Inner<'a>> for BencodeRef<'a> {
25 fn from(val: Inner<'a>) -> Self {
26 BencodeRef { inner: val }
27 }
28}
29
30#[derive(Debug, Eq, PartialEq, Clone, Hash)]
32pub struct BencodeRef<'a> {
33 inner: Inner<'a>,
34}
35
36impl<'a> BencodeRef<'a> {
37 #[allow(clippy::missing_errors_doc)]
39 pub fn decode(bytes: &'a [u8], opts: BDecodeOpt) -> BencodeParseResult<BencodeRef<'a>> {
40 let (bencode, end_pos) = decode::decode(bytes, 0, opts, 0)?;
42
43 if end_pos != bytes.len() && opts.enforce_full_decode() {
44 return Err(BencodeParseError::BytesEmpty { pos: end_pos });
45 }
46
47 Ok(bencode)
48 }
49
50 #[must_use]
52 pub fn buffer(&self) -> &'a [u8] {
53 #[allow(clippy::match_same_arms)]
54 match self.inner {
55 Inner::Int(_, buffer) => buffer,
56 Inner::Bytes(_, buffer) => buffer,
57 Inner::List(_, buffer) => buffer,
58 Inner::Dict(_, buffer) => buffer,
59 }
60 }
61}
62
63impl<'a> BRefAccess for BencodeRef<'a> {
64 type BKey = &'a [u8];
65 type BType = BencodeRef<'a>;
66
67 fn kind<'b>(&'b self) -> RefKind<'b, &'a [u8], BencodeRef<'a>> {
68 match self.inner {
69 Inner::Int(n, _) => RefKind::Int(n),
70 Inner::Bytes(n, _) => RefKind::Bytes(n),
71 Inner::List(ref n, _) => RefKind::List(n),
72 Inner::Dict(ref n, _) => RefKind::Dict(n),
73 }
74 }
75
76 fn str(&self) -> Option<&str> {
77 self.str_ext()
78 }
79
80 fn int(&self) -> Option<i64> {
81 match self.inner {
82 Inner::Int(n, _) => Some(n),
83 _ => None,
84 }
85 }
86
87 fn bytes(&self) -> Option<&[u8]> {
88 self.bytes_ext()
89 }
90
91 fn list(&self) -> Option<&dyn BListAccess<BencodeRef<'a>>> {
92 match self.inner {
93 Inner::List(ref n, _) => Some(n),
94 _ => None,
95 }
96 }
97
98 fn dict(&self) -> Option<&dyn BDictAccess<&'a [u8], BencodeRef<'a>>> {
99 match self.inner {
100 Inner::Dict(ref n, _) => Some(n),
101 _ => None,
102 }
103 }
104}
105
106impl<'a> BRefAccessExt<'a> for BencodeRef<'a> {
107 fn str_ext(&self) -> Option<&'a str> {
108 let bytes = self.bytes_ext()?;
109
110 match str::from_utf8(bytes) {
111 Ok(n) => Some(n),
112 Err(_) => None,
113 }
114 }
115
116 fn bytes_ext(&self) -> Option<&'a [u8]> {
117 match self.inner {
118 Inner::Bytes(n, _) => Some(&n[0..]),
119 _ => None,
120 }
121 }
122}
123
124#[cfg(test)]
125mod tests {
126
127 use crate::access::bencode::BRefAccess;
128 use crate::reference::bencode_ref::BencodeRef;
129 use crate::reference::decode_opt::BDecodeOpt;
130
131 #[test]
132 fn positive_int_buffer() {
133 let int_bytes = b"i-500e"; let bencode = BencodeRef::decode(&int_bytes[..], BDecodeOpt::default()).unwrap();
135
136 assert_eq!(int_bytes, bencode.buffer());
137 }
138
139 #[test]
140 fn positive_bytes_buffer() {
141 let bytes_bytes = b"3:asd"; let bencode = BencodeRef::decode(&bytes_bytes[..], BDecodeOpt::default()).unwrap();
143
144 assert_eq!(bytes_bytes, bencode.buffer());
145 }
146
147 #[test]
148 fn positive_list_buffer() {
149 let list_bytes = b"l3:asde"; let bencode = BencodeRef::decode(&list_bytes[..], BDecodeOpt::default()).unwrap();
151
152 assert_eq!(list_bytes, bencode.buffer());
153 }
154
155 #[test]
156 fn positive_dict_buffer() {
157 let dict_bytes = b"d3:asd3:asde"; let bencode = BencodeRef::decode(&dict_bytes[..], BDecodeOpt::default()).unwrap();
159
160 assert_eq!(dict_bytes, bencode.buffer());
161 }
162
163 #[test]
164 fn positive_list_nested_int_buffer() {
165 let nested_int_bytes = b"li-500ee"; let bencode = BencodeRef::decode(&nested_int_bytes[..], BDecodeOpt::default()).unwrap();
167
168 let bencode_list = bencode.list().unwrap();
169 let bencode_int = bencode_list.get(0).unwrap();
170
171 let int_bytes = b"i-500e"; assert_eq!(int_bytes, bencode_int.buffer());
173 }
174
175 #[test]
176 fn positive_dict_nested_int_buffer() {
177 let nested_int_bytes = b"d3:asdi-500ee"; let bencode = BencodeRef::decode(&nested_int_bytes[..], BDecodeOpt::default()).unwrap();
179
180 let bencode_dict = bencode.dict().unwrap();
181 let bencode_int = bencode_dict.lookup(&b"asd"[..]).unwrap();
183
184 let int_bytes = b"i-500e"; assert_eq!(int_bytes, bencode_int.buffer());
186 }
187
188 #[test]
189 fn positive_list_nested_bytes_buffer() {
190 let nested_bytes_bytes = b"l3:asde"; let bencode = BencodeRef::decode(&nested_bytes_bytes[..], BDecodeOpt::default()).unwrap();
192
193 let bencode_list = bencode.list().unwrap();
194 let bencode_bytes = bencode_list.get(0).unwrap();
195
196 let bytes_bytes = b"3:asd"; assert_eq!(bytes_bytes, bencode_bytes.buffer());
198 }
199
200 #[test]
201 fn positive_dict_nested_bytes_buffer() {
202 let nested_bytes_bytes = b"d3:asd3:asde"; let bencode = BencodeRef::decode(&nested_bytes_bytes[..], BDecodeOpt::default()).unwrap();
204
205 let bencode_dict = bencode.dict().unwrap();
206 let bencode_bytes = bencode_dict.lookup(&b"asd"[..]).unwrap();
208
209 let bytes_bytes = b"3:asd"; assert_eq!(bytes_bytes, bencode_bytes.buffer());
211 }
212
213 #[test]
214 fn positive_list_nested_list_buffer() {
215 let nested_list_bytes = b"ll3:asdee"; let bencode = BencodeRef::decode(&nested_list_bytes[..], BDecodeOpt::default()).unwrap();
217
218 let bencode_list = bencode.list().unwrap();
219 let bencode_list = bencode_list.get(0).unwrap();
220
221 let list_bytes = b"l3:asde"; assert_eq!(list_bytes, bencode_list.buffer());
223 }
224
225 #[test]
226 fn positive_dict_nested_list_buffer() {
227 let nested_list_bytes = b"d3:asdl3:asdee"; let bencode = BencodeRef::decode(&nested_list_bytes[..], BDecodeOpt::default()).unwrap();
229
230 let bencode_dict = bencode.dict().unwrap();
231 let bencode_list = bencode_dict.lookup(&b"asd"[..]).unwrap();
233
234 let list_bytes = b"l3:asde"; assert_eq!(list_bytes, bencode_list.buffer());
236 }
237
238 #[test]
239 fn positive_list_nested_dict_buffer() {
240 let nested_dict_bytes = b"ld3:asd3:asdee"; let bencode = BencodeRef::decode(&nested_dict_bytes[..], BDecodeOpt::default()).unwrap();
242
243 let bencode_list = bencode.list().unwrap();
244 let bencode_dict = bencode_list.get(0).unwrap();
245
246 let dict_bytes = b"d3:asd3:asde"; assert_eq!(dict_bytes, bencode_dict.buffer());
248 }
249
250 #[test]
251 fn positive_dict_nested_dict_buffer() {
252 let nested_dict_bytes = b"d3:asdd3:asd3:asdee"; let bencode = BencodeRef::decode(&nested_dict_bytes[..], BDecodeOpt::default()).unwrap();
254
255 let bencode_dict = bencode.dict().unwrap();
256 let bencode_dict = bencode_dict.lookup(&b"asd"[..]).unwrap();
258
259 let dict_bytes = b"d3:asd3:asde"; assert_eq!(dict_bytes, bencode_dict.buffer());
261 }
262}