torrust_tracker_contrib_bencode/mutable/
bencode_mut.rs

1use std::borrow::Cow;
2use std::collections::BTreeMap;
3use std::str;
4
5use crate::access::bencode::{BMutAccess, BRefAccess, MutKind, RefKind};
6use crate::access::dict::BDictAccess;
7use crate::access::list::BListAccess;
8use crate::mutable::encode;
9
10/// Bencode object that holds references to the underlying data.
11#[derive(Debug, Eq, PartialEq, Clone, Hash)]
12pub enum Inner<'a> {
13    /// Bencode Integer.
14    Int(i64),
15    /// Bencode Bytes.
16    Bytes(Cow<'a, [u8]>),
17    /// Bencode List.
18    List(Vec<BencodeMut<'a>>),
19    /// Bencode Dictionary.
20    Dict(BTreeMap<Cow<'a, [u8]>, BencodeMut<'a>>),
21}
22
23/// `BencodeMut` object that stores references to some data.
24#[derive(Debug, Eq, PartialEq, Clone, Hash)]
25pub struct BencodeMut<'a> {
26    inner: Inner<'a>,
27}
28
29impl<'a> BencodeMut<'a> {
30    fn new(inner: Inner<'a>) -> BencodeMut<'a> {
31        BencodeMut { inner }
32    }
33
34    /// Create a new `BencodeMut` representing an `i64`.
35    #[must_use]
36    pub fn new_int(value: i64) -> BencodeMut<'a> {
37        BencodeMut::new(Inner::Int(value))
38    }
39
40    /// Create a new `BencodeMut` representing a `[u8]`.
41    #[must_use]
42    pub fn new_bytes(value: Cow<'a, [u8]>) -> BencodeMut<'a> {
43        BencodeMut::new(Inner::Bytes(value))
44    }
45
46    /// Create a new `BencodeMut` representing a `BListAccess`.
47    #[must_use]
48    pub fn new_list() -> BencodeMut<'a> {
49        BencodeMut::new(Inner::List(Vec::new()))
50    }
51
52    /// Create a new `BencodeMut` representing a `BDictAccess`.
53    #[must_use]
54    pub fn new_dict() -> BencodeMut<'a> {
55        BencodeMut::new(Inner::Dict(BTreeMap::new()))
56    }
57
58    /// Encode the `BencodeMut` into a buffer representing the bencode.
59    #[must_use]
60    pub fn encode(&self) -> Vec<u8> {
61        let mut buffer = Vec::new();
62
63        encode::encode(self, &mut buffer);
64
65        buffer
66    }
67}
68
69impl<'a> BRefAccess for BencodeMut<'a> {
70    type BKey = Cow<'a, [u8]>;
71    type BType = BencodeMut<'a>;
72
73    fn kind<'b>(&'b self) -> RefKind<'b, Cow<'a, [u8]>, BencodeMut<'a>> {
74        match self.inner {
75            Inner::Int(n) => RefKind::Int(n),
76            Inner::Bytes(ref n) => RefKind::Bytes(n),
77            Inner::List(ref n) => RefKind::List(n),
78            Inner::Dict(ref n) => RefKind::Dict(n),
79        }
80    }
81
82    fn str(&self) -> Option<&str> {
83        let bytes = self.bytes()?;
84
85        match str::from_utf8(bytes) {
86            Ok(n) => Some(n),
87            Err(_) => None,
88        }
89    }
90
91    fn int(&self) -> Option<i64> {
92        match self.inner {
93            Inner::Int(n) => Some(n),
94            _ => None,
95        }
96    }
97
98    fn bytes(&self) -> Option<&[u8]> {
99        match self.inner {
100            Inner::Bytes(ref n) => Some(n.as_ref()),
101            _ => None,
102        }
103    }
104
105    fn list(&self) -> Option<&dyn BListAccess<BencodeMut<'a>>> {
106        match self.inner {
107            Inner::List(ref n) => Some(n),
108            _ => None,
109        }
110    }
111
112    fn dict(&self) -> Option<&dyn BDictAccess<Cow<'a, [u8]>, BencodeMut<'a>>> {
113        match self.inner {
114            Inner::Dict(ref n) => Some(n),
115            _ => None,
116        }
117    }
118}
119
120impl<'a> BMutAccess for BencodeMut<'a> {
121    fn kind_mut<'b>(&'b mut self) -> MutKind<'b, Cow<'a, [u8]>, BencodeMut<'a>> {
122        match self.inner {
123            Inner::Int(n) => MutKind::Int(n),
124            Inner::Bytes(ref mut n) => MutKind::Bytes((*n).as_ref()),
125            Inner::List(ref mut n) => MutKind::List(n),
126            Inner::Dict(ref mut n) => MutKind::Dict(n),
127        }
128    }
129
130    fn list_mut(&mut self) -> Option<&mut dyn BListAccess<BencodeMut<'a>>> {
131        match self.inner {
132            Inner::List(ref mut n) => Some(n),
133            _ => None,
134        }
135    }
136
137    fn dict_mut(&mut self) -> Option<&mut dyn BDictAccess<Cow<'a, [u8]>, BencodeMut<'a>>> {
138        match self.inner {
139            Inner::Dict(ref mut n) => Some(n),
140            _ => None,
141        }
142    }
143}
144
145// impl<'a> From<BencodeRef<'a>> for BencodeMut<'a> {
146//     fn from(value: BencodeRef<'a>) -> Self {
147//         let inner = match value.kind() {
148//             BencodeRefKind::Int(value) => InnerBencodeMut::Int(value),
149//             BencodeRefKind::Bytes(value) => InnerBencodeMut::Bytes(Cow::Owned(Vec::from(value))),
150//             BencodeRefKind::List(value) => {
151//                 InnerBencodeMut::List(value.clone().into_iter().map(|b| BencodeMut::from(b.clone())).collect())
152//             }
153//             BencodeRefKind::Dict(value) => InnerBencodeMut::Dict(
154//                 value
155//                     .to_list()
156//                     .into_iter()
157//                     .map(|(key, value)| (Cow::Owned(Vec::from(*key)), BencodeMut::from(value.clone())))
158//                     .collect(),
159//             ),
160//         };
161//         BencodeMut { inner }
162//     }
163// }
164
165#[cfg(test)]
166mod test {
167    use crate::access::bencode::BMutAccess;
168    use crate::mutable::bencode_mut::BencodeMut;
169
170    #[test]
171    fn positive_int_encode() {
172        let bencode_int = BencodeMut::new_int(-560);
173
174        let int_bytes = b"i-560e"; // cspell:disable-line
175        assert_eq!(&int_bytes[..], &bencode_int.encode()[..]);
176    }
177
178    #[test]
179    fn positive_bytes_encode() {
180        /* cspell:disable-next-line */
181        let bencode_bytes = BencodeMut::new_bytes((&b"asdasd"[..]).into());
182
183        let bytes_bytes = b"6:asdasd"; // cspell:disable-line
184        assert_eq!(&bytes_bytes[..], &bencode_bytes.encode()[..]);
185    }
186
187    #[test]
188    fn positive_empty_list_encode() {
189        let bencode_list = BencodeMut::new_list();
190
191        let list_bytes = b"le"; // cspell:disable-line
192        assert_eq!(&list_bytes[..], &bencode_list.encode()[..]);
193    }
194
195    #[test]
196    fn positive_nonempty_list_encode() {
197        let mut bencode_list = BencodeMut::new_list();
198
199        {
200            let list_mut = bencode_list.list_mut().unwrap();
201            list_mut.push(BencodeMut::new_int(56));
202        }
203
204        let list_bytes = b"li56ee"; // cspell:disable-line
205        assert_eq!(&list_bytes[..], &bencode_list.encode()[..]);
206    }
207
208    #[test]
209    fn positive_empty_dict_encode() {
210        let bencode_dict = BencodeMut::new_dict();
211
212        let dict_bytes = b"de"; // cspell:disable-line
213        assert_eq!(&dict_bytes[..], &bencode_dict.encode()[..]);
214    }
215
216    #[test]
217    fn positive_nonempty_dict_encode() {
218        let mut bencode_dict = BencodeMut::new_dict();
219
220        {
221            let dict_mut = bencode_dict.dict_mut().unwrap();
222            /* cspell:disable-next-line */
223            dict_mut.insert((&b"asd"[..]).into(), BencodeMut::new_bytes((&b"asdasd"[..]).into()));
224        }
225
226        let dict_bytes = b"d3:asd6:asdasde"; // cspell:disable-line
227        assert_eq!(&dict_bytes[..], &bencode_dict.encode()[..]);
228    }
229}