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}