bip_bencode/reference/
bencode_ref.rs

1use access::bencode::BRefAccessExt;
2use std::collections::BTreeMap;
3use std::str;
4
5use access::bencode::{BRefAccess, BencodeRefKind};
6use reference::decode;
7use reference::decode_opt::BDecodeOpt;
8use access::dict::BDictAccess;
9use access::list::BListAccess;
10use error::{BencodeParseResult, BencodeParseError, BencodeParseErrorKind};
11
12/// Bencode object that holds references to the underlying data.
13#[derive(Debug, Eq, PartialEq, Clone, Hash)]
14pub enum InnerBencodeRef<'a> {
15    /// Bencode Integer.
16    Int(i64, &'a [u8]),
17    /// Bencode Bytes.
18    Bytes(&'a [u8], &'a [u8]),
19    /// Bencode List.
20    List(Vec<BencodeRef<'a>>, &'a [u8]),
21    /// Bencode Dictionary.
22    Dict(BTreeMap<&'a [u8], BencodeRef<'a>>, &'a [u8]),
23}
24
25impl<'a> Into<BencodeRef<'a>> for InnerBencodeRef<'a> {
26    fn into(self) -> BencodeRef<'a> {
27        BencodeRef{ inner: self }
28    }
29}
30
31/// `BencodeRef` object that stores references to some buffer.
32#[derive(Debug, Eq, PartialEq, Clone, Hash)]
33pub struct BencodeRef<'a> {
34    inner: InnerBencodeRef<'a>
35}
36
37impl<'a> BencodeRef<'a> {
38    /// Decode the given bytes into a `BencodeRef` using the given decode options.
39    pub fn decode(bytes: &'a [u8], opts: BDecodeOpt) -> BencodeParseResult<BencodeRef<'a>> {
40        // Apply try so any errors return before the eof check
41        let (bencode, end_pos) = try!(decode::decode(bytes, 0, opts, 0));
42
43        if end_pos != bytes.len() && opts.enforce_full_decode() {
44            return Err(BencodeParseError::from_kind(BencodeParseErrorKind::BytesEmpty{ pos: end_pos }));
45        }
46
47        Ok(bencode)
48    }
49
50    /// Get a byte slice of the current bencode byte representation.
51    pub fn buffer(&self) -> &'a [u8] {
52        match self.inner {
53            InnerBencodeRef::Int(_, buffer)   => buffer,
54            InnerBencodeRef::Bytes(_, buffer) => buffer,
55            InnerBencodeRef::List(_, buffer)  => buffer,
56            InnerBencodeRef::Dict(_, buffer)  => buffer
57        }
58    }
59}
60
61impl<'a> BRefAccess for BencodeRef<'a> {
62    type BKey  = &'a [u8];
63    type BType = BencodeRef<'a>;
64
65    fn kind<'b>(&'b self) -> BencodeRefKind<'b, &'a [u8], BencodeRef<'a>> {
66        match self.inner {
67            InnerBencodeRef::Int(n, _)       => BencodeRefKind::Int(n),
68            InnerBencodeRef::Bytes(ref n, _) => BencodeRefKind::Bytes(n),
69            InnerBencodeRef::List(ref n, _)  => BencodeRefKind::List(n),
70            InnerBencodeRef::Dict(ref n, _)  => BencodeRefKind::Dict(n),
71        }
72    }
73
74    fn str(&self) -> Option<&str> {
75        self.str_ext()
76    }
77
78    fn int(&self) -> Option<i64> {
79        match self.inner {
80            InnerBencodeRef::Int(n, _) => Some(n),
81            _ => None,
82        }
83    }
84
85    fn bytes(&self) -> Option<&[u8]> {
86        self.bytes_ext()
87    }
88
89    fn list(&self) -> Option<&BListAccess<BencodeRef<'a>>> {
90        match self.inner {
91            InnerBencodeRef::List(ref n, _) => Some(n),
92            _ => None,
93        }
94    }
95
96    fn dict(&self) -> Option<&BDictAccess<&'a [u8], BencodeRef<'a>>> {
97        match self.inner {
98            InnerBencodeRef::Dict(ref n, _) => Some(n),
99            _ => None,
100        }
101    }
102}
103
104impl<'a> BRefAccessExt<'a> for BencodeRef<'a> {
105    fn str_ext(&self) -> Option<&'a str> {
106        let bytes = match self.bytes_ext() {
107            Some(n) => n,
108            None => return None,
109        };
110
111        match str::from_utf8(bytes) {
112            Ok(n) => Some(n),
113            Err(_) => None,
114        }
115    }
116
117    fn bytes_ext(&self) -> Option<&'a [u8]> {
118        match self.inner {
119            InnerBencodeRef::Bytes(ref n, _) => Some(&n[0..]),
120            _ => None,
121        }
122    }
123}
124
125#[cfg(test)]
126mod tests {
127    use std::default::Default;
128
129    use access::bencode::BRefAccess;
130    use reference::bencode_ref::BencodeRef;
131    use reference::decode_opt::BDecodeOpt;
132
133    #[test]
134    fn positive_int_buffer() {
135        let int_bytes = b"i-500e";
136        let bencode = BencodeRef::decode(&int_bytes[..], BDecodeOpt::default()).unwrap();
137
138        assert_eq!(int_bytes, bencode.buffer());
139    }
140
141    #[test]
142    fn positive_bytes_buffer() {
143        let bytes_bytes = b"3:asd";
144        let bencode = BencodeRef::decode(&bytes_bytes[..], BDecodeOpt::default()).unwrap();
145
146        assert_eq!(bytes_bytes, bencode.buffer());
147    }
148
149    #[test]
150    fn positive_list_buffer() {
151        let list_bytes = b"l3:asde";
152        let bencode = BencodeRef::decode(&list_bytes[..], BDecodeOpt::default()).unwrap();
153
154        assert_eq!(list_bytes, bencode.buffer());
155    }
156
157    #[test]
158    fn positive_dict_buffer() {
159        let dict_bytes = b"d3:asd3:asde";
160        let bencode = BencodeRef::decode(&dict_bytes[..], BDecodeOpt::default()).unwrap();
161
162        assert_eq!(dict_bytes, bencode.buffer());
163    }
164
165    #[test]
166    fn positive_list_nested_int_buffer() {
167        let nested_int_bytes = b"li-500ee";
168        let bencode = BencodeRef::decode(&nested_int_bytes[..], BDecodeOpt::default()).unwrap();
169
170        let bencode_list = bencode.list().unwrap();
171        let bencode_int = bencode_list.get(0).unwrap();
172
173        let int_bytes = b"i-500e";
174        assert_eq!(int_bytes, bencode_int.buffer());
175    }
176
177    #[test]
178    fn positive_dict_nested_int_buffer() {
179        let nested_int_bytes = b"d3:asdi-500ee";
180        let bencode = BencodeRef::decode(&nested_int_bytes[..], BDecodeOpt::default()).unwrap();
181
182        let bencode_dict = bencode.dict().unwrap();
183        let bencode_int = bencode_dict.lookup(&b"asd"[..]).unwrap();
184
185        let int_bytes = b"i-500e";
186        assert_eq!(int_bytes, bencode_int.buffer());
187    }
188
189    #[test]
190    fn positive_list_nested_bytes_buffer() {
191        let nested_bytes_bytes = b"l3:asde";
192        let bencode = BencodeRef::decode(&nested_bytes_bytes[..], BDecodeOpt::default()).unwrap();
193
194        let bencode_list = bencode.list().unwrap();
195        let bencode_bytes = bencode_list.get(0).unwrap();
196
197        let bytes_bytes = b"3:asd";
198        assert_eq!(bytes_bytes, bencode_bytes.buffer());
199    }
200
201    #[test]
202    fn positive_dict_nested_bytes_buffer() {
203        let nested_bytes_bytes = b"d3:asd3:asde";
204        let bencode = BencodeRef::decode(&nested_bytes_bytes[..], BDecodeOpt::default()).unwrap();
205
206        let bencode_dict = bencode.dict().unwrap();
207        let bencode_bytes = bencode_dict.lookup(&b"asd"[..]).unwrap();
208
209        let bytes_bytes = b"3:asd";
210        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";
216        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";
222        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";
228        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();
232
233        let list_bytes = b"l3:asde";
234        assert_eq!(list_bytes, bencode_list.buffer());
235    }
236
237    #[test]
238    fn positive_list_nested_dict_buffer() {
239        let nested_dict_bytes = b"ld3:asd3:asdee";
240        let bencode = BencodeRef::decode(&nested_dict_bytes[..], BDecodeOpt::default()).unwrap();
241
242        let bencode_list = bencode.list().unwrap();
243        let bencode_dict = bencode_list.get(0).unwrap();
244
245        let dict_bytes = b"d3:asd3:asde";
246        assert_eq!(dict_bytes, bencode_dict.buffer());
247    }
248
249    #[test]
250    fn positive_dict_nested_dict_buffer() {
251        let nested_dict_bytes = b"d3:asdd3:asd3:asdee";
252        let bencode = BencodeRef::decode(&nested_dict_bytes[..], BDecodeOpt::default()).unwrap();
253
254        let bencode_dict = bencode.dict().unwrap();
255        let bencode_dict = bencode_dict.lookup(&b"asd"[..]).unwrap();
256
257        let dict_bytes = b"d3:asd3:asde";
258        assert_eq!(dict_bytes, bencode_dict.buffer());
259    }
260}