bendy/decoding/object.rs
1use crate::{
2 decoding::{DictDecoder, Error, ListDecoder},
3 state_tracker::Token,
4};
5
6/// An object read from a decoder
7pub enum Object<'obj, 'ser: 'obj> {
8 /// A list of arbitrary objects
9 List(ListDecoder<'obj, 'ser>),
10 /// A map of string-valued keys to arbitrary objects
11 Dict(DictDecoder<'obj, 'ser>),
12 /// An unparsed integer
13 Integer(&'ser str),
14 /// A byte string
15 Bytes(&'ser [u8]),
16}
17
18impl<'obj, 'ser: 'obj> Object<'obj, 'ser> {
19 pub fn into_token(self) -> Token<'ser> {
20 match self {
21 Object::List(_) => Token::List,
22 Object::Dict(_) => Token::Dict,
23 Object::Bytes(bytes) => Token::String(bytes),
24 Object::Integer(num) => Token::Num(num),
25 }
26 }
27
28 /// Try to treat the object as a byte string, mapping [`Object::Bytes(v)`] into
29 /// [`Ok(v)`]. Any other variant returns the given default value.
30 ///
31 /// Default arguments passed into `bytes_or` are eagerly evaluated; if you
32 /// are passing the result of a function call, it is recommended to use
33 /// [`bytes_or_else`], which is lazily evaluated.
34 ///
35 /// [`Object::Bytes(v)`]: self::Object::Bytes
36 /// [`Ok(v)`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok
37 /// [`bytes_or_else`]: self::Object::bytes_or_else
38 ///
39 /// # Examples
40 ///
41 /// ```
42 /// use bendy::decoding::Object;
43 ///
44 /// let x = Object::Bytes(b"foo");
45 /// assert_eq!(Ok(&b"foo"[..]), x.bytes_or(Err("failure")));
46 ///
47 /// let x = Object::Integer("foo");
48 /// assert_eq!(Err("failure"), x.bytes_or(Err("failure")));
49 /// ```
50 pub fn bytes_or<ErrorT>(
51 self,
52 default: Result<&'ser [u8], ErrorT>,
53 ) -> Result<&'ser [u8], ErrorT> {
54 match self {
55 Object::Bytes(content) => Ok(content),
56 _ => default,
57 }
58 }
59
60 /// Try to treat the object as a byte string, mapping [`Object::Bytes(v)`] into
61 /// [`Ok(v)`]. Any other variant is passed into the given fallback method.
62 ///
63 /// [`Object::Bytes(v)`]: self::Object::Bytes
64 /// [`Ok(v)`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok
65 ///
66 /// # Examples
67 ///
68 /// ```
69 /// use bendy::decoding::Object;
70 ///
71 /// let x = Object::Bytes(b"foo");
72 /// assert_eq!(
73 /// Ok(&b"foo"[..]),
74 /// x.bytes_or_else(|obj| Err(obj.into_token().name()))
75 /// );
76 ///
77 /// let x = Object::Integer("foo");
78 /// assert_eq!(
79 /// Err("Num"),
80 /// x.bytes_or_else(|obj| Err(obj.into_token().name()))
81 /// );
82 /// ```
83 pub fn bytes_or_else<ErrorT>(
84 self,
85 op: impl FnOnce(Self) -> Result<&'ser [u8], ErrorT>,
86 ) -> Result<&'ser [u8], ErrorT> {
87 match self {
88 Object::Bytes(content) => Ok(content),
89 _ => op(self),
90 }
91 }
92
93 /// Try to treat the object as a byte string, mapping [`Object::Bytes(v)`] into
94 /// [`Ok(v)`]. Any other variant results in an [`Error::UnexpectedElement`].
95 ///
96 /// [`Object::Bytes(v)`]: self::Object::Bytes
97 /// [`Ok(v)`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok
98 /// [`Error::UnexpectedElement`]: self::Error::UnexpectedElement
99 ///
100 /// # Examples
101 ///
102 /// ```
103 /// use bendy::decoding::Object;
104 ///
105 /// let x = Object::Bytes(b"foo");
106 /// assert_eq!(b"foo", x.try_into_bytes().unwrap());
107 ///
108 /// let x = Object::Integer("foo");
109 /// assert!(x.try_into_bytes().is_err());
110 /// ```
111 pub fn try_into_bytes(self) -> Result<&'ser [u8], Error> {
112 self.bytes_or_else(|obj| Err(Error::unexpected_token("String", obj.into_token().name())))
113 }
114
115 /// Try to treat the object as an integer and return the internal string representation,
116 /// mapping [`Object::Integer(v)`] into [`Ok(v)`]. Any other variant returns the given
117 /// default value.
118 ///
119 /// Default arguments passed into `integer_or` are eagerly evaluated; if you are passing
120 /// the result of a function call, it is recommended to use [`integer_or_else`], which
121 /// is lazily evaluated.
122 ///
123 /// [`Object::Integer(v)`]: self::Object::Integer
124 /// [`Ok(v)`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok
125 /// [`integer_or_else`]: self::Object::integer_or_else
126 ///
127 /// # Examples
128 ///
129 /// ```
130 /// use bendy::decoding::Object;
131 ///
132 /// let x = Object::Integer("123");
133 /// assert_eq!(Ok(&"123"[..]), x.integer_or(Err("failure")));
134 ///
135 /// let x = Object::Bytes(b"foo");
136 /// assert_eq!(Err("failure"), x.integer_or(Err("failure")));
137 /// ```
138 pub fn integer_or<ErrorT>(
139 self,
140 default: Result<&'ser str, ErrorT>,
141 ) -> Result<&'ser str, ErrorT> {
142 match self {
143 Object::Integer(content) => Ok(content),
144 _ => default,
145 }
146 }
147
148 /// Try to treat the object as an integer and return the internal string representation,
149 /// mapping [`Object::Integer(v)`] into [`Ok(v)`]. Any other variant is passed into the
150 /// given fallback method.
151 ///
152 /// [`Object::Integer(v)`]: self::Object::Integer
153 /// [`Ok(v)`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok
154 ///
155 /// # Examples
156 ///
157 /// ```
158 /// use bendy::decoding::Object;
159 ///
160 /// let x = Object::Integer("123");
161 /// assert_eq!(
162 /// Ok(&"123"[..]),
163 /// x.integer_or_else(|obj| Err(obj.into_token().name()))
164 /// );
165 ///
166 /// let x = Object::Bytes(b"foo");
167 /// assert_eq!(
168 /// Err("String"),
169 /// x.integer_or_else(|obj| Err(obj.into_token().name()))
170 /// );
171 /// ```
172 pub fn integer_or_else<ErrorT>(
173 self,
174 op: impl FnOnce(Self) -> Result<&'ser str, ErrorT>,
175 ) -> Result<&'ser str, ErrorT> {
176 match self {
177 Object::Integer(content) => Ok(content),
178 _ => op(self),
179 }
180 }
181
182 /// Try to treat the object as an integer and return the internal string representation,
183 /// mapping [`Object::Integer(v)`] into [`Ok(v)`]. Any other variant results in an
184 /// [`Error::UnexpectedElement`].
185 ///
186 /// [`Object::Integer(v)`]: self::Object::Integer
187 /// [`Ok(v)`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok
188 /// [`Error::UnexpectedElement`]: self::Error::UnexpectedElement
189 ///
190 /// # Examples
191 ///
192 /// ```
193 /// use bendy::decoding::Object;
194 ///
195 /// let x = Object::Integer("123");
196 /// assert_eq!("123", x.try_into_integer().unwrap());
197 ///
198 /// let x = Object::Bytes(b"foo");
199 /// assert!(x.try_into_integer().is_err());
200 /// ```
201 pub fn try_into_integer(self) -> Result<&'ser str, Error> {
202 self.integer_or_else(|obj| Err(Error::unexpected_token("Num", obj.into_token().name())))
203 }
204
205 /// Try to treat the object as a list and return the internal list content decoder,
206 /// mapping [`Object::List(v)`] into [`Ok(v)`]. Any other variant returns the given
207 /// default value.
208 ///
209 /// Default arguments passed into `list_or` are eagerly evaluated; if you are passing
210 /// the result of a function call, it is recommended to use [`list_or_else`], which is
211 /// lazily evaluated.
212 ///
213 /// [`Object::List(v)`]: self::Object::List
214 /// [`Ok(v)`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok
215 /// [`list_or_else`]: self::Object::list_or_else
216 ///
217 /// # Examples
218 ///
219 /// ```
220 /// use bendy::decoding::{Decoder, Object};
221 ///
222 /// let mut list_decoder = Decoder::new(b"le");
223 /// let x = list_decoder.next_object().unwrap().unwrap();
224 ///
225 /// assert!(x.list_or(Err("failure")).is_ok());
226 ///
227 /// let x = Object::Bytes(b"foo");
228 /// assert_eq!("failure", x.list_or(Err("failure")).unwrap_err());
229 /// ```
230 pub fn list_or<ErrorT>(
231 self,
232 default: Result<ListDecoder<'obj, 'ser>, ErrorT>,
233 ) -> Result<ListDecoder<'obj, 'ser>, ErrorT> {
234 match self {
235 Object::List(content) => Ok(content),
236 _ => default,
237 }
238 }
239
240 /// Try to treat the object as a list and return the internal list content decoder,
241 /// mapping [`Object::List(v)`] into [`Ok(v)`]. Any other variant is passed into the
242 /// given fallback method.
243 ///
244 /// [`Object::List(v)`]: self::Object::List
245 /// [`Ok(v)`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok
246 ///
247 /// # Examples
248 ///
249 /// ```
250 /// use bendy::decoding::{Decoder, Object};
251 ///
252 /// let mut list_decoder = Decoder::new(b"le");
253 /// let x = list_decoder.next_object().unwrap().unwrap();
254 ///
255 /// assert!(x.list_or_else(|obj| Err(obj.into_token().name())).is_ok());
256 ///
257 /// let x = Object::Bytes(b"foo");
258 /// assert_eq!(
259 /// "String",
260 /// x.list_or_else(|obj| Err(obj.into_token().name()))
261 /// .unwrap_err()
262 /// );
263 /// ```
264 pub fn list_or_else<ErrorT>(
265 self,
266 op: impl FnOnce(Self) -> Result<ListDecoder<'obj, 'ser>, ErrorT>,
267 ) -> Result<ListDecoder<'obj, 'ser>, ErrorT> {
268 match self {
269 Object::List(content) => Ok(content),
270 _ => op(self),
271 }
272 }
273
274 /// Try to treat the object as a list and return the internal list content decoder,
275 /// mapping [`Object::List(v)`] into [`Ok(v)`]. Any other variant results in an
276 /// [`Error::UnexpectedElement`].
277 ///
278 /// [`Object::List(v)`]: self::Object::List
279 /// [`Ok(v)`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok
280 /// [`Error::UnexpectedElement`]: self::Error::UnexpectedElement
281 ///
282 /// # Examples
283 ///
284 /// ```
285 /// use bendy::decoding::{Decoder, Object};
286 ///
287 /// let mut list_decoder = Decoder::new(b"le");
288 /// let x = list_decoder.next_object().unwrap().unwrap();
289 ///
290 /// assert!(x.try_into_list().is_ok());
291 ///
292 /// let x = Object::Bytes(b"foo");
293 /// assert!(x.try_into_list().is_err());
294 /// ```
295 pub fn try_into_list(self) -> Result<ListDecoder<'obj, 'ser>, Error> {
296 self.list_or_else(|obj| Err(Error::unexpected_token("List", obj.into_token().name())))
297 }
298
299 /// Try to treat the object as a dictionary and return the internal dictionary content
300 /// decoder, mapping [`Object::Dict(v)`] into [`Ok(v)`]. Any other variant returns the
301 /// given default value.
302 ///
303 /// Default arguments passed to `dictionary_or` are eagerly evaluated; if you are passing
304 /// the result of a function call, it is recommended to use [`dictionary_or_else`], which
305 /// is lazily evaluated.
306 ///
307 /// [`Object::Dict(v)`]: self::Object::Dict
308 /// [`Ok(v)`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok
309 /// [`dictionary_or_else`]: self::Object::dictionary_or_else
310 ///
311 /// # Examples
312 ///
313 /// ```
314 /// use bendy::decoding::{Decoder, Object};
315 ///
316 /// let mut dict_decoder = Decoder::new(b"de");
317 /// let x = dict_decoder.next_object().unwrap().unwrap();
318 ///
319 /// assert!(x.dictionary_or(Err("failure")).is_ok());
320 ///
321 /// let x = Object::Bytes(b"foo");
322 /// assert_eq!("failure", x.dictionary_or(Err("failure")).unwrap_err());
323 /// ```
324 pub fn dictionary_or<ErrorT>(
325 self,
326 default: Result<DictDecoder<'obj, 'ser>, ErrorT>,
327 ) -> Result<DictDecoder<'obj, 'ser>, ErrorT> {
328 match self {
329 Object::Dict(content) => Ok(content),
330 _ => default,
331 }
332 }
333
334 /// Try to treat the object as a dictionary and return the internal dictionary content
335 /// decoder, mapping [`Object::Dict(v)`] into [`Ok(v)`]. Any other variant is passed
336 /// into the given fallback method.
337 ///
338 /// [`Object::Dict(v)`]: self::Object::Dict
339 /// [`Ok(v)`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok
340 ///
341 /// # Examples
342 ///
343 /// ```
344 /// use bendy::decoding::{Decoder, Object};
345 ///
346 /// let mut dict_decoder = Decoder::new(b"de");
347 /// let x = dict_decoder.next_object().unwrap().unwrap();
348 ///
349 /// assert!(x
350 /// .dictionary_or_else(|obj| Err(obj.into_token().name()))
351 /// .is_ok());
352 ///
353 /// let x = Object::Bytes(b"foo");
354 /// assert_eq!(
355 /// "String",
356 /// x.dictionary_or_else(|obj| Err(obj.into_token().name()))
357 /// .unwrap_err()
358 /// );
359 /// ```
360 pub fn dictionary_or_else<ErrorT>(
361 self,
362 op: impl FnOnce(Self) -> Result<DictDecoder<'obj, 'ser>, ErrorT>,
363 ) -> Result<DictDecoder<'obj, 'ser>, ErrorT> {
364 match self {
365 Object::Dict(content) => Ok(content),
366 _ => op(self),
367 }
368 }
369
370 /// Try to treat the object as a dictionary and return the internal dictionary content
371 /// decoder, mapping [`Object::Dict(v)`] into [`Ok(v)`]. Any other variant results in
372 /// an [`Error::UnexpectedElement`].
373 ///
374 /// [`Object::Dict(v)`]: self::Object::Dict
375 /// [`Ok(v)`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok
376 /// [`Error::UnexpectedElement`]: self::Error::UnexpectedElement
377 ///
378 /// # Examples
379 ///
380 /// ```
381 /// use bendy::decoding::{Decoder, Object};
382 ///
383 /// let mut dict_decoder = Decoder::new(b"de");
384 /// let x = dict_decoder.next_object().unwrap().unwrap();
385 ///
386 /// assert!(x.try_into_dictionary().is_ok());
387 ///
388 /// let x = Object::Bytes(b"foo");
389 /// assert!(x.try_into_dictionary().is_err());
390 /// ```
391 pub fn try_into_dictionary(self) -> Result<DictDecoder<'obj, 'ser>, Error> {
392 self.dictionary_or_else(|obj| Err(Error::unexpected_token("Dict", obj.into_token().name())))
393 }
394}