serde_json_core/de/
mod.rs

1//! Deserialize JSON data to a Rust data structure
2
3use core::str::FromStr;
4use core::{fmt, str};
5
6use serde::de::{self, Visitor};
7use serde::Serialize;
8
9use self::enum_::{UnitVariantAccess, VariantAccess};
10use self::map::MapAccess;
11use self::seq::SeqAccess;
12
13mod enum_;
14mod map;
15mod seq;
16
17/// Deserialization result
18pub type Result<T> = core::result::Result<T, Error>;
19
20/// This type represents all possible errors that can occur when deserializing JSON data
21#[derive(Debug, PartialEq, Eq, Clone, Serialize)]
22#[cfg_attr(not(feature = "custom-error-messages"), derive(Copy))]
23#[cfg_attr(feature = "defmt", derive(defmt::Format))]
24#[non_exhaustive]
25pub enum Error {
26    /// Can’t parse a value without knowing its expected type.
27    AnyIsUnsupported,
28
29    /// Cannot parse a sequence of bytes.
30    BytesIsUnsupported,
31
32    /// EOF while parsing a list.
33    EofWhileParsingList,
34
35    /// EOF while parsing an object.
36    EofWhileParsingObject,
37
38    /// EOF while parsing a string.
39    EofWhileParsingString,
40
41    /// EOF while parsing a JSON number.
42    EofWhileParsingNumber,
43
44    /// EOF while parsing a JSON value.
45    EofWhileParsingValue,
46
47    /// Expected this character to be a `':'`.
48    ExpectedColon,
49
50    /// Expected this character to be either a `','` or a `']'`.
51    ExpectedListCommaOrEnd,
52
53    /// Expected this character to be either a `','` or a `'}'`.
54    ExpectedObjectCommaOrEnd,
55
56    /// Expected to parse either a `true`, `false`, or a `null`.
57    ExpectedSomeIdent,
58
59    /// Expected this character to start a JSON value.
60    ExpectedSomeValue,
61
62    /// Invalid number.
63    InvalidNumber,
64
65    /// Invalid type
66    InvalidType,
67
68    /// Invalid unicode code point.
69    InvalidUnicodeCodePoint,
70
71    /// Invalid String Escape Sequence
72    InvalidEscapeSequence,
73
74    /// Escaped String length exceeds buffer size
75    EscapedStringIsTooLong,
76
77    /// Object key is not a string.
78    KeyMustBeAString,
79
80    /// JSON has non-whitespace trailing characters after the value.
81    TrailingCharacters,
82
83    /// JSON has a comma after the last value in an array or map.
84    TrailingComma,
85
86    /// Error with a custom message that we had to discard.
87    CustomError,
88
89    /// Error with a custom message that was preserved.
90    #[cfg(feature = "custom-error-messages")]
91    CustomErrorWithMessage(
92        #[cfg_attr(feature = "defmt", defmt(Debug2Format))] heapless::String<64>,
93    ),
94}
95
96impl serde::de::StdError for Error {}
97
98impl From<crate::str::StringUnescapeError> for Error {
99    fn from(error: crate::str::StringUnescapeError) -> Self {
100        match error {
101            crate::str::StringUnescapeError::InvalidEscapeSequence => Self::InvalidEscapeSequence,
102        }
103    }
104}
105
106/// A structure that deserializes Rust values from JSON in a buffer.
107pub struct Deserializer<'b, 's> {
108    slice: &'b [u8],
109    index: usize,
110    string_unescape_buffer: Option<&'s mut [u8]>,
111}
112
113impl<'a, 's> Deserializer<'a, 's> {
114    /// Create a new `Deserializer`, optionally with a buffer to use to unescape strings.
115    /// If not present, strings are not unescaped.
116    pub fn new(
117        slice: &'a [u8],
118        string_unescape_buffer: Option<&'s mut [u8]>,
119    ) -> Deserializer<'a, 's> {
120        Deserializer {
121            slice,
122            index: 0,
123            string_unescape_buffer,
124        }
125    }
126
127    fn eat_char(&mut self) {
128        self.index += 1;
129    }
130
131    /// Check whether there is any unexpected data left in the buffer
132    /// and return the amount of data consumed
133    pub fn end(&mut self) -> Result<usize> {
134        match self.parse_whitespace() {
135            Some(_) => Err(Error::TrailingCharacters),
136            None => Ok(self.index),
137        }
138    }
139
140    fn end_seq(&mut self) -> Result<()> {
141        match self.parse_whitespace().ok_or(Error::EofWhileParsingList)? {
142            b']' => {
143                self.eat_char();
144                Ok(())
145            }
146            b',' => {
147                self.eat_char();
148                match self.parse_whitespace() {
149                    Some(b']') => Err(Error::TrailingComma),
150                    _ => Err(Error::TrailingCharacters),
151                }
152            }
153            _ => Err(Error::TrailingCharacters),
154        }
155    }
156
157    fn end_map(&mut self) -> Result<()> {
158        match self
159            .parse_whitespace()
160            .ok_or(Error::EofWhileParsingObject)?
161        {
162            b'}' => {
163                self.eat_char();
164                Ok(())
165            }
166            b',' => Err(Error::TrailingComma),
167            _ => Err(Error::TrailingCharacters),
168        }
169    }
170
171    fn next_char(&mut self) -> Option<u8> {
172        let ch = self.slice.get(self.index);
173
174        if ch.is_some() {
175            self.index += 1;
176        }
177
178        ch.cloned()
179    }
180
181    fn parse_ident(&mut self, ident: &[u8]) -> Result<()> {
182        for c in ident {
183            if Some(*c) != self.next_char() {
184                return Err(Error::ExpectedSomeIdent);
185            }
186        }
187
188        Ok(())
189    }
190
191    fn parse_object_colon(&mut self) -> Result<()> {
192        match self
193            .parse_whitespace()
194            .ok_or(Error::EofWhileParsingObject)?
195        {
196            b':' => {
197                self.eat_char();
198                Ok(())
199            }
200            _ => Err(Error::ExpectedColon),
201        }
202    }
203
204    /// Parse a string, returning the escaped string.
205    fn parse_str(&mut self) -> Result<&'a str> {
206        if self.parse_whitespace().ok_or(Error::EofWhileParsingValue)? == b'"' {
207            self.eat_char();
208        } else {
209            return Err(Error::InvalidType);
210        }
211
212        let start = self.index;
213        loop {
214            match self.peek() {
215                Some(b'"') => {
216                    // Counts the number of backslashes in front of the current index.
217                    //
218                    // "some string with \\\" included."
219                    //                  ^^^^^
220                    //                  |||||
221                    //       loop run:  4321|
222                    //                      |
223                    //                   `index`
224                    //
225                    // Since we only get in this code branch if we found a " starting the string and `index` is greater
226                    // than the start position, we know the loop will end no later than this point.
227                    let leading_backslashes = |index: usize| -> usize {
228                        let mut count = 0;
229                        loop {
230                            if self.slice[index - count - 1] == b'\\' {
231                                count += 1;
232                            } else {
233                                return count;
234                            }
235                        }
236                    };
237
238                    let is_escaped = leading_backslashes(self.index) % 2 == 1;
239                    if is_escaped {
240                        self.eat_char(); // just continue
241                    } else {
242                        let end = self.index;
243                        self.eat_char();
244
245                        return str::from_utf8(&self.slice[start..end])
246                            .map_err(|_| Error::InvalidUnicodeCodePoint);
247                    }
248                }
249                Some(_) => self.eat_char(),
250                None => return Err(Error::EofWhileParsingString),
251            }
252        }
253    }
254
255    /// Consumes all the whitespace characters and returns a peek into the next character
256    fn parse_whitespace(&mut self) -> Option<u8> {
257        loop {
258            match self.peek() {
259                Some(b' ') | Some(b'\n') | Some(b'\t') | Some(b'\r') => {
260                    self.eat_char();
261                }
262                other => {
263                    return other;
264                }
265            }
266        }
267    }
268
269    fn peek(&mut self) -> Option<u8> {
270        self.slice.get(self.index).cloned()
271    }
272}
273
274// NOTE(deserialize_*signed) we avoid parsing into u64 and then casting to a smaller integer, which
275// is what upstream does, to avoid pulling in 64-bit compiler intrinsics, which waste a few KBs of
276// Flash, when targeting non 64-bit architectures
277macro_rules! deserialize_unsigned {
278    ($self:ident, $visitor:ident, $uxx:ident, $visit_uxx:ident) => {{
279        let peek = $self
280            .parse_whitespace()
281            .ok_or(Error::EofWhileParsingValue)?;
282
283        match peek {
284            b'-' => Err(Error::InvalidNumber),
285            b'0' => {
286                $self.eat_char();
287                $visitor.$visit_uxx(0)
288            }
289            b'1'..=b'9' => {
290                $self.eat_char();
291
292                let mut number = (peek - b'0') as $uxx;
293                loop {
294                    match $self.peek() {
295                        Some(c @ b'0'..=b'9') => {
296                            $self.eat_char();
297                            number = number
298                                .checked_mul(10)
299                                .ok_or(Error::InvalidNumber)?
300                                .checked_add((c - b'0') as $uxx)
301                                .ok_or(Error::InvalidNumber)?;
302                        }
303                        _ => return $visitor.$visit_uxx(number),
304                    }
305                }
306            }
307            _ => Err(Error::InvalidType),
308        }
309    }};
310}
311
312macro_rules! deserialize_signed {
313    ($self:ident, $visitor:ident, $ixx:ident, $visit_ixx:ident) => {{
314        let signed = match $self
315            .parse_whitespace()
316            .ok_or(Error::EofWhileParsingValue)?
317        {
318            b'-' => {
319                $self.eat_char();
320                true
321            }
322            _ => false,
323        };
324
325        match $self.peek().ok_or(Error::EofWhileParsingValue)? {
326            b'0' => {
327                $self.eat_char();
328                $visitor.$visit_ixx(0)
329            }
330            c @ b'1'..=b'9' => {
331                $self.eat_char();
332
333                let mut number = (c - b'0') as $ixx * if signed { -1 } else { 1 };
334                loop {
335                    match $self.peek() {
336                        Some(c @ b'0'..=b'9') => {
337                            $self.eat_char();
338                            number = number
339                                .checked_mul(10)
340                                .ok_or(Error::InvalidNumber)?
341                                .checked_add((c - b'0') as $ixx * if signed { -1 } else { 1 })
342                                .ok_or(Error::InvalidNumber)?;
343                        }
344                        _ => return $visitor.$visit_ixx(number),
345                    }
346                }
347            }
348            _ => return Err(Error::InvalidType),
349        }
350    }};
351}
352
353macro_rules! deserialize_fromstr {
354    ($self:ident, $visitor:ident, $typ:ident, $visit_fn:ident, $pattern:expr) => {{
355        match $self.parse_whitespace().ok_or(Error::EofWhileParsingValue)? {
356            b'n' => {
357                $self.eat_char();
358                $self.parse_ident(b"ull")?;
359                $visitor.$visit_fn($typ::NAN)
360            }
361            _ => {
362                let start = $self.index;
363                while $self.peek().is_some() {
364                    let c = $self.peek().unwrap();
365                    if $pattern.iter().find(|&&d| d == c).is_some() {
366                        $self.eat_char();
367                    } else {
368                        break;
369                    }
370                }
371
372                // Note(unsafe): We already checked that it only contains ascii. This is only true if the
373                // caller has guaranteed that `pattern` contains only ascii characters.
374                let s = unsafe { str::from_utf8_unchecked(&$self.slice[start..$self.index]) };
375
376                let v = $typ::from_str(s).or(Err(Error::InvalidNumber))?;
377
378                $visitor.$visit_fn(v)
379            }
380        }
381    }};
382}
383
384impl<'a, 'de, 's> de::Deserializer<'de> for &'a mut Deserializer<'de, 's> {
385    type Error = Error;
386
387    /// Unsupported. Can’t parse a value without knowing its expected type.
388    fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value>
389    where
390        V: Visitor<'de>,
391    {
392        Err(Error::AnyIsUnsupported)
393    }
394
395    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
396    where
397        V: Visitor<'de>,
398    {
399        let peek = self.parse_whitespace().ok_or(Error::EofWhileParsingValue)?;
400
401        match peek {
402            b't' => {
403                self.eat_char();
404                self.parse_ident(b"rue")?;
405                visitor.visit_bool(true)
406            }
407            b'f' => {
408                self.eat_char();
409                self.parse_ident(b"alse")?;
410                visitor.visit_bool(false)
411            }
412            _ => Err(Error::InvalidType),
413        }
414    }
415
416    fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value>
417    where
418        V: Visitor<'de>,
419    {
420        deserialize_signed!(self, visitor, i8, visit_i8)
421    }
422
423    fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value>
424    where
425        V: Visitor<'de>,
426    {
427        deserialize_signed!(self, visitor, i16, visit_i16)
428    }
429
430    fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value>
431    where
432        V: Visitor<'de>,
433    {
434        deserialize_signed!(self, visitor, i32, visit_i32)
435    }
436
437    fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value>
438    where
439        V: Visitor<'de>,
440    {
441        deserialize_signed!(self, visitor, i64, visit_i64)
442    }
443
444    fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>
445    where
446        V: Visitor<'de>,
447    {
448        deserialize_unsigned!(self, visitor, u8, visit_u8)
449    }
450
451    fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value>
452    where
453        V: Visitor<'de>,
454    {
455        deserialize_unsigned!(self, visitor, u16, visit_u16)
456    }
457
458    fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value>
459    where
460        V: Visitor<'de>,
461    {
462        deserialize_unsigned!(self, visitor, u32, visit_u32)
463    }
464
465    fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value>
466    where
467        V: Visitor<'de>,
468    {
469        deserialize_unsigned!(self, visitor, u64, visit_u64)
470    }
471
472    fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
473    where
474        V: Visitor<'de>,
475    {
476        deserialize_fromstr!(self, visitor, f32, visit_f32, b"0123456789+-.eE")
477    }
478
479    fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value>
480    where
481        V: Visitor<'de>,
482    {
483        deserialize_fromstr!(self, visitor, f64, visit_f64, b"0123456789+-.eE")
484    }
485
486    fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
487    where
488        V: Visitor<'de>,
489    {
490        self.deserialize_str(visitor)
491    }
492
493    fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
494    where
495        V: Visitor<'de>,
496    {
497        let escaped_string = self.parse_str()?;
498
499        // If the unescape buffer is not provided, skip unescaping strings
500        let Some(string_unescape_buffer) = self.string_unescape_buffer.as_deref_mut() else {
501            return visitor.visit_borrowed_str(escaped_string);
502        };
503
504        // If the escaped string doesn't contain '\\', it' can't have any escaped characters
505        if !escaped_string.as_bytes().contains(&b'\\') {
506            return visitor.visit_borrowed_str(escaped_string);
507        }
508
509        let mut string_unescape_buffer_write_position = 0;
510
511        for fragment in crate::str::EscapedStr(escaped_string).fragments() {
512            let char_encode_buffer = &mut [0; 4];
513
514            let unescaped_bytes = match fragment? {
515                crate::str::EscapedStringFragment::NotEscaped(fragment) => fragment.as_bytes(),
516                crate::str::EscapedStringFragment::Escaped(c) => {
517                    c.encode_utf8(char_encode_buffer).as_bytes()
518                }
519            };
520
521            string_unescape_buffer[string_unescape_buffer_write_position..]
522                .get_mut(..unescaped_bytes.len())
523                .ok_or(Error::EscapedStringIsTooLong)?
524                .copy_from_slice(unescaped_bytes);
525
526            string_unescape_buffer_write_position += unescaped_bytes.len();
527        }
528
529        visitor.visit_str(
530            str::from_utf8(&string_unescape_buffer[..string_unescape_buffer_write_position])
531                .map_err(|_| Error::InvalidUnicodeCodePoint)?,
532        )
533    }
534
535    /// Unsupported. String is not available in no-std.
536    fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
537    where
538        V: Visitor<'de>,
539    {
540        self.deserialize_str(visitor)
541    }
542
543    /// Unsupported
544    fn deserialize_bytes<V>(self, _visitor: V) -> Result<V::Value>
545    where
546        V: Visitor<'de>,
547    {
548        Err(Error::BytesIsUnsupported)
549    }
550
551    /// Unsupported
552    fn deserialize_byte_buf<V>(self, _visitor: V) -> Result<V::Value>
553    where
554        V: Visitor<'de>,
555    {
556        Err(Error::BytesIsUnsupported)
557    }
558
559    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
560    where
561        V: Visitor<'de>,
562    {
563        match self.parse_whitespace().ok_or(Error::EofWhileParsingValue)? {
564            b'n' => {
565                self.eat_char();
566                self.parse_ident(b"ull")?;
567                visitor.visit_none()
568            }
569            _ => visitor.visit_some(self),
570        }
571    }
572
573    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
574    where
575        V: Visitor<'de>,
576    {
577        let peek = match self.parse_whitespace() {
578            Some(b) => b,
579            None => {
580                return Err(Error::EofWhileParsingValue);
581            }
582        };
583
584        match peek {
585            b'n' => {
586                self.eat_char();
587                self.parse_ident(b"ull")?;
588                visitor.visit_unit()
589            }
590            _ => Err(Error::InvalidType),
591        }
592    }
593
594    fn deserialize_unit_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
595    where
596        V: Visitor<'de>,
597    {
598        self.deserialize_unit(visitor)
599    }
600
601    fn deserialize_newtype_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
602    where
603        V: Visitor<'de>,
604    {
605        // If the newtype struct is an `EscapedStr`...
606        if name == crate::str::EscapedStr::NAME {
607            // ...deserialize as an escaped string instead.
608
609            struct EscapedStringDeserializer<'a, 'de, 's>(&'a mut Deserializer<'de, 's>);
610
611            impl<'a, 'de, 's> serde::Deserializer<'de> for EscapedStringDeserializer<'a, 'de, 's> {
612                type Error = Error;
613
614                fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
615                where
616                    V: Visitor<'de>,
617                {
618                    // The only structure which is deserialized at this point is an `EscapedStr`,
619                    // so pass the escaped string to its implementation of visit_borrowed_str.
620                    // This line defacto becomes `Ok(EscapedStr(self.0.parse_str()?))`.
621                    visitor.visit_borrowed_str(self.0.parse_str()?)
622                }
623
624                // `EscapedStr` only deserializes strings, so we might as well forward all methods to `deserialize_any`.
625                serde::forward_to_deserialize_any! {
626                    bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
627                    bytes byte_buf option unit unit_struct newtype_struct seq tuple
628                    tuple_struct map struct enum identifier ignored_any
629                }
630            }
631
632            visitor.visit_newtype_struct(EscapedStringDeserializer(self))
633        } else {
634            visitor.visit_newtype_struct(self)
635        }
636    }
637
638    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
639    where
640        V: Visitor<'de>,
641    {
642        match self.parse_whitespace().ok_or(Error::EofWhileParsingValue)? {
643            b'[' => {
644                self.eat_char();
645                let ret = visitor.visit_seq(SeqAccess::new(self))?;
646
647                self.end_seq()?;
648
649                Ok(ret)
650            }
651            _ => Err(Error::InvalidType),
652        }
653    }
654
655    fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value>
656    where
657        V: Visitor<'de>,
658    {
659        self.deserialize_seq(visitor)
660    }
661
662    fn deserialize_tuple_struct<V>(
663        self,
664        _name: &'static str,
665        _len: usize,
666        visitor: V,
667    ) -> Result<V::Value>
668    where
669        V: Visitor<'de>,
670    {
671        self.deserialize_seq(visitor)
672    }
673
674    fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
675    where
676        V: Visitor<'de>,
677    {
678        let peek = self.parse_whitespace().ok_or(Error::EofWhileParsingValue)?;
679
680        if peek == b'{' {
681            self.eat_char();
682
683            let ret = visitor.visit_map(MapAccess::new(self))?;
684
685            self.end_map()?;
686
687            Ok(ret)
688        } else {
689            Err(Error::InvalidType)
690        }
691    }
692
693    fn deserialize_struct<V>(
694        self,
695        _name: &'static str,
696        _fields: &'static [&'static str],
697        visitor: V,
698    ) -> Result<V::Value>
699    where
700        V: Visitor<'de>,
701    {
702        self.deserialize_map(visitor)
703    }
704
705    fn deserialize_enum<V>(
706        self,
707        _name: &'static str,
708        _variants: &'static [&'static str],
709        visitor: V,
710    ) -> Result<V::Value>
711    where
712        V: Visitor<'de>,
713    {
714        match self.parse_whitespace().ok_or(Error::EofWhileParsingValue)? {
715            b'"' => visitor.visit_enum(UnitVariantAccess::new(self)),
716            b'{' => {
717                self.eat_char();
718                let value = visitor.visit_enum(VariantAccess::new(self))?;
719                match self.parse_whitespace().ok_or(Error::EofWhileParsingValue)? {
720                    b'}' => {
721                        self.eat_char();
722                        Ok(value)
723                    }
724                    _ => Err(Error::ExpectedSomeValue),
725                }
726            }
727            _ => Err(Error::ExpectedSomeValue),
728        }
729    }
730
731    fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
732    where
733        V: Visitor<'de>,
734    {
735        self.deserialize_str(visitor)
736    }
737
738    /// Used to throw out fields from JSON objects that we don’t want to
739    /// keep in our structs.
740    fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value>
741    where
742        V: Visitor<'de>,
743    {
744        match self.parse_whitespace().ok_or(Error::EofWhileParsingValue)? {
745            b'"' => self.deserialize_str(visitor),
746            b'[' => self.deserialize_seq(visitor),
747            b'{' => self.deserialize_struct("ignored", &[], visitor),
748            b',' | b'}' | b']' => Err(Error::ExpectedSomeValue),
749            // If it’s something else then we chomp until we get to an end delimiter.
750            // This does technically allow for illegal JSON since we’re just ignoring
751            // characters rather than parsing them.
752            _ => loop {
753                match self.peek() {
754                    // The visitor is expected to be UnknownAny’s visitor, which
755                    // implements visit_unit to return its unit Ok result.
756                    Some(b',') | Some(b'}') | Some(b']') => break visitor.visit_unit(),
757                    Some(_) => self.eat_char(),
758                    None => break Err(Error::EofWhileParsingString),
759                }
760            },
761        }
762    }
763}
764
765impl de::Error for Error {
766    #[cfg_attr(not(feature = "custom-error-messages"), allow(unused_variables))]
767    fn custom<T>(msg: T) -> Self
768    where
769        T: fmt::Display,
770    {
771        #[cfg(not(feature = "custom-error-messages"))]
772        {
773            Error::CustomError
774        }
775        #[cfg(feature = "custom-error-messages")]
776        {
777            use core::fmt::Write;
778
779            let mut string = heapless::String::new();
780            write!(string, "{:.64}", msg).unwrap();
781            Error::CustomErrorWithMessage(string)
782        }
783    }
784}
785
786impl fmt::Display for Error {
787    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
788        write!(
789            f,
790            "{}",
791            match self {
792                Error::EofWhileParsingList => "EOF while parsing a list.",
793                Error::EofWhileParsingObject => "EOF while parsing an object.",
794                Error::EofWhileParsingString => "EOF while parsing a string.",
795                Error::EofWhileParsingValue => "EOF while parsing a JSON value.",
796                Error::ExpectedColon => "Expected this character to be a `':'`.",
797                Error::ExpectedListCommaOrEnd => {
798                    "Expected this character to be either a `','` or\
799                     a \
800                     `']'`."
801                }
802                Error::ExpectedObjectCommaOrEnd => {
803                    "Expected this character to be either a `','` \
804                     or a \
805                     `'}'`."
806                }
807                Error::ExpectedSomeIdent => {
808                    "Expected to parse either a `true`, `false`, or a \
809                     `null`."
810                }
811                Error::ExpectedSomeValue => "Expected this character to start a JSON value.",
812                Error::InvalidNumber => "Invalid number.",
813                Error::InvalidType => "Invalid type",
814                Error::InvalidUnicodeCodePoint => "Invalid unicode code point.",
815                Error::KeyMustBeAString => "Object key is not a string.",
816                Error::TrailingCharacters => {
817                    "JSON has non-whitespace trailing characters after \
818                     the \
819                     value."
820                }
821                Error::TrailingComma => "JSON has a comma after the last value in an array or map.",
822                Error::CustomError => "JSON does not match deserializer’s expected format.",
823                #[cfg(feature = "custom-error-messages")]
824                Error::CustomErrorWithMessage(msg) => msg.as_str(),
825                _ => "Invalid JSON",
826            }
827        )
828    }
829}
830
831fn from_slice_maybe_escaped<'a, T>(
832    v: &'a [u8],
833    string_unescape_buffer: Option<&mut [u8]>,
834) -> Result<(T, usize)>
835where
836    T: de::Deserialize<'a>,
837{
838    let mut de = Deserializer::new(v, string_unescape_buffer);
839    let value = de::Deserialize::deserialize(&mut de)?;
840    let length = de.end()?;
841
842    Ok((value, length))
843}
844
845/// Deserializes an instance of type `T` from bytes of JSON text, using the provided buffer to unescape strings
846/// Returns the value and the number of bytes consumed in the process
847pub fn from_slice_escaped<'a, T>(
848    v: &'a [u8],
849    string_unescape_buffer: &mut [u8],
850) -> Result<(T, usize)>
851where
852    T: de::Deserialize<'a>,
853{
854    from_slice_maybe_escaped(v, Some(string_unescape_buffer))
855}
856
857/// Deserializes an instance of type `T` from bytes of JSON text
858/// Returns the value and the number of bytes consumed in the process
859pub fn from_slice<'a, T>(v: &'a [u8]) -> Result<(T, usize)>
860where
861    T: de::Deserialize<'a>,
862{
863    from_slice_maybe_escaped(v, None)
864}
865
866/// Deserializes an instance of type T from a string of JSON text, using the provided buffer to unescape strings
867pub fn from_str_escaped<'a, T>(s: &'a str, string_unescape_buffer: &mut [u8]) -> Result<(T, usize)>
868where
869    T: de::Deserialize<'a>,
870{
871    from_slice_escaped(s.as_bytes(), string_unescape_buffer)
872}
873
874/// Deserializes an instance of type T from a string of JSON text
875pub fn from_str<'a, T>(s: &'a str) -> Result<(T, usize)>
876where
877    T: de::Deserialize<'a>,
878{
879    from_slice(s.as_bytes())
880}
881
882#[cfg(test)]
883mod tests {
884    use serde_derive::Deserialize;
885
886    #[derive(Debug, Deserialize, PartialEq)]
887    enum Type {
888        #[serde(rename = "boolean")]
889        Boolean,
890        #[serde(rename = "number")]
891        Number,
892        #[serde(rename = "thing")]
893        Thing,
894    }
895
896    #[test]
897    fn array() {
898        assert_eq!(crate::from_str::<[i32; 0]>("[]"), Ok(([], 2)));
899        assert_eq!(crate::from_str("[0, 1, 2]"), Ok(([0, 1, 2], 9)));
900
901        // errors
902        assert!(crate::from_str::<[i32; 2]>("[0, 1,]").is_err());
903    }
904
905    #[test]
906    fn bool() {
907        assert_eq!(crate::from_str("true"), Ok((true, 4)));
908        assert_eq!(crate::from_str(" true"), Ok((true, 5)));
909        assert_eq!(crate::from_str("true "), Ok((true, 5)));
910
911        assert_eq!(crate::from_str("false"), Ok((false, 5)));
912        assert_eq!(crate::from_str(" false"), Ok((false, 6)));
913        assert_eq!(crate::from_str("false "), Ok((false, 6)));
914
915        // errors
916        assert!(crate::from_str::<bool>("true false").is_err());
917        assert!(crate::from_str::<bool>("tru").is_err());
918    }
919
920    #[test]
921    fn floating_point() {
922        assert_eq!(crate::from_str("5.0"), Ok((5.0, 3)));
923        assert_eq!(crate::from_str("1"), Ok((1.0, 1)));
924        assert_eq!(crate::from_str("1e5"), Ok((1e5, 3)));
925        assert!(crate::from_str::<f32>("a").is_err());
926        assert!(crate::from_str::<f32>(",").is_err());
927    }
928
929    #[test]
930    fn integer() {
931        assert_eq!(crate::from_str("5"), Ok((5, 1)));
932        assert_eq!(crate::from_str("101"), Ok((101, 3)));
933        assert!(crate::from_str::<u16>("1e5").is_err());
934        assert!(crate::from_str::<u8>("256").is_err());
935        assert!(crate::from_str::<f32>(",").is_err());
936    }
937
938    #[test]
939    fn enum_clike() {
940        assert_eq!(crate::from_str(r#" "boolean" "#), Ok((Type::Boolean, 11)));
941        assert_eq!(crate::from_str(r#" "number" "#), Ok((Type::Number, 10)));
942        assert_eq!(crate::from_str(r#" "thing" "#), Ok((Type::Thing, 9)));
943    }
944
945    #[test]
946    fn char() {
947        fn from_str_test<'de, T: serde::Deserialize<'de>>(
948            s: &'de str,
949        ) -> super::Result<(T, usize)> {
950            crate::from_str_escaped(s, &mut [0; 8])
951        }
952
953        assert_eq!(from_str_test(r#""n""#), Ok(('n', 3)));
954        assert_eq!(from_str_test(r#""\"""#), Ok(('"', 4)));
955        assert_eq!(from_str_test(r#""\\""#), Ok(('\\', 4)));
956        assert_eq!(from_str_test(r#""/""#), Ok(('/', 3)));
957        assert_eq!(from_str_test(r#""\b""#), Ok(('\x08', 4)));
958        assert_eq!(from_str_test(r#""\f""#), Ok(('\x0C', 4)));
959        assert_eq!(from_str_test(r#""\n""#), Ok(('\n', 4)));
960        assert_eq!(from_str_test(r#""\r""#), Ok(('\r', 4)));
961        assert_eq!(from_str_test(r#""\t""#), Ok(('\t', 4)));
962        assert_eq!(from_str_test(r#""\u000b""#), Ok(('\x0B', 8)));
963        assert_eq!(from_str_test(r#""\u000B""#), Ok(('\x0B', 8)));
964        assert_eq!(from_str_test(r#""Σ""#), Ok(('Σ', 4)));
965    }
966
967    #[test]
968    fn str() {
969        // No escaping, so can borrow from the input
970        assert_eq!(crate::from_str(r#" "hello" "#), Ok(("hello", 9)));
971        assert_eq!(crate::from_str(r#" "" "#), Ok(("", 4)));
972        assert_eq!(crate::from_str(r#" " " "#), Ok((" ", 5)));
973        assert_eq!(crate::from_str(r#" "👏" "#), Ok(("👏", 8)));
974
975        fn s(s: &'static str) -> heapless::String<1024> {
976            s.parse().expect("Failed to create test string")
977        }
978
979        fn from_str_test<'de, T: serde::Deserialize<'de>>(
980            s: &'de str,
981        ) -> super::Result<(T, usize)> {
982            crate::from_str_escaped(s, &mut [0; 16])
983        }
984
985        // escaped " in the string content
986        assert_eq!(from_str_test(r#" "foo\"bar" "#), Ok((s(r#"foo"bar"#), 12)));
987        assert_eq!(
988            from_str_test(r#" "foo\\\"bar" "#),
989            Ok((s(r#"foo\"bar"#), 14))
990        );
991        assert_eq!(
992            from_str_test(r#" "foo\"\"bar" "#),
993            Ok((s(r#"foo""bar"#), 14))
994        );
995        assert_eq!(from_str_test(r#" "\"bar" "#), Ok((s(r#""bar"#), 9)));
996        assert_eq!(from_str_test(r#" "foo\"" "#), Ok((s(r#"foo""#), 9)));
997        assert_eq!(from_str_test(r#" "\"" "#), Ok((s(r#"""#), 6)));
998
999        // non-excaped " preceded by backslashes
1000        assert_eq!(
1001            from_str_test(r#" "foo bar\\" "#),
1002            Ok((s(r#"foo bar\"#), 13))
1003        );
1004        assert_eq!(
1005            from_str_test(r#" "foo bar\\\\" "#),
1006            Ok((s(r#"foo bar\\"#), 15))
1007        );
1008        assert_eq!(
1009            from_str_test(r#" "foo bar\\\\\\" "#),
1010            Ok((s(r#"foo bar\\\"#), 17))
1011        );
1012        assert_eq!(
1013            from_str_test(r#" "foo bar\\\\\\\\" "#),
1014            Ok((s(r#"foo bar\\\\"#), 19))
1015        );
1016        assert_eq!(from_str_test(r#" "\\" "#), Ok((s(r#"\"#), 6)));
1017    }
1018
1019    #[test]
1020    fn tuple_of_str() {
1021        fn s(s: &'static str) -> heapless::String<1024> {
1022            s.parse().expect("Failed to create test string")
1023        }
1024
1025        fn from_str_test<'de, T: serde::Deserialize<'de>>(
1026            s: &'de str,
1027        ) -> super::Result<(T, usize)> {
1028            crate::from_str_escaped(s, &mut [0; 16])
1029        }
1030
1031        // The combined length of the first and third strings are longer than the buffer, but that's OK,
1032        // as escaped strings are deserialized into owned str types, e.g. `heapless::String`.
1033        // The second string is longer than the buffer, but that's OK, as strings which aren't escaped
1034        // are deserialized as str's borrowed from the input
1035
1036        assert_eq!(
1037            from_str_test(
1038                r#" [ "AAAAAAAAAAAA\n", "BBBBBBBBBBBBBBBBBBBBBBBB", "CCCCCCCCCCCC\n" ] "#
1039            ),
1040            Ok((
1041                (
1042                    s("AAAAAAAAAAAA\n"),
1043                    "BBBBBBBBBBBBBBBBBBBBBBBB",
1044                    s("CCCCCCCCCCCC\n")
1045                ),
1046                68
1047            ))
1048        );
1049    }
1050
1051    #[test]
1052    fn escaped_str() {
1053        assert_eq!(
1054            crate::from_str(r#""Hello\nWorld""#),
1055            Ok((crate::str::EscapedStr(r#"Hello\nWorld"#), 14))
1056        );
1057    }
1058
1059    #[test]
1060    fn struct_bool() {
1061        #[derive(Debug, Deserialize, PartialEq)]
1062        struct Led {
1063            led: bool,
1064        }
1065
1066        assert_eq!(
1067            crate::from_str(r#"{ "led": true }"#),
1068            Ok((Led { led: true }, 15))
1069        );
1070        assert_eq!(
1071            crate::from_str(r#"{ "led": false }"#),
1072            Ok((Led { led: false }, 16))
1073        );
1074    }
1075
1076    #[test]
1077    fn struct_i8() {
1078        #[derive(Debug, Deserialize, PartialEq)]
1079        struct Temperature {
1080            temperature: i8,
1081        }
1082
1083        assert_eq!(
1084            crate::from_str(r#"{ "temperature": -17 }"#),
1085            Ok((Temperature { temperature: -17 }, 22))
1086        );
1087
1088        assert_eq!(
1089            crate::from_str(r#"{ "temperature": -0 }"#),
1090            Ok((Temperature { temperature: -0 }, 21))
1091        );
1092
1093        assert_eq!(
1094            crate::from_str(r#"{ "temperature": 0 }"#),
1095            Ok((Temperature { temperature: 0 }, 20))
1096        );
1097
1098        // out of range
1099        assert!(crate::from_str::<Temperature>(r#"{ "temperature": 128 }"#).is_err());
1100        assert!(crate::from_str::<Temperature>(r#"{ "temperature": -129 }"#).is_err());
1101    }
1102
1103    #[test]
1104    fn struct_f32() {
1105        #[derive(Debug, Deserialize, PartialEq)]
1106        struct Temperature {
1107            temperature: f32,
1108        }
1109
1110        assert_eq!(
1111            crate::from_str(r#"{ "temperature": -17.2 }"#),
1112            Ok((Temperature { temperature: -17.2 }, 24))
1113        );
1114
1115        assert_eq!(
1116            crate::from_str(r#"{ "temperature": -0.0 }"#),
1117            Ok((Temperature { temperature: -0. }, 23))
1118        );
1119
1120        assert_eq!(
1121            crate::from_str(r#"{ "temperature": -2.1e-3 }"#),
1122            Ok((
1123                Temperature {
1124                    temperature: -2.1e-3
1125                },
1126                26
1127            ))
1128        );
1129
1130        assert_eq!(
1131            crate::from_str(r#"{ "temperature": -3 }"#),
1132            Ok((Temperature { temperature: -3. }, 21))
1133        );
1134
1135        use core::f32;
1136
1137        assert_eq!(
1138            crate::from_str(r#"{ "temperature": -1e500 }"#),
1139            Ok((
1140                Temperature {
1141                    temperature: f32::NEG_INFINITY
1142                },
1143                25
1144            ))
1145        );
1146
1147        // NaNs will always compare unequal.
1148        let (r, n): (Temperature, usize) = crate::from_str(r#"{ "temperature": null }"#).unwrap();
1149        assert!(r.temperature.is_nan());
1150        assert_eq!(n, 23);
1151
1152        assert!(crate::from_str::<Temperature>(r#"{ "temperature": 1e1e1 }"#).is_err());
1153        assert!(crate::from_str::<Temperature>(r#"{ "temperature": -2-2 }"#).is_err());
1154        assert!(crate::from_str::<Temperature>(r#"{ "temperature": 1 1 }"#).is_err());
1155        assert!(crate::from_str::<Temperature>(r#"{ "temperature": 0.0. }"#).is_err());
1156        assert!(crate::from_str::<Temperature>(r#"{ "temperature": ä }"#).is_err());
1157        assert!(crate::from_str::<Temperature>(r#"{ "temperature": None }"#).is_err());
1158    }
1159
1160    #[test]
1161    fn struct_option() {
1162        #[derive(Debug, Deserialize, PartialEq)]
1163        struct Property<'a> {
1164            #[serde(borrow)]
1165            description: Option<&'a str>,
1166        }
1167
1168        assert_eq!(
1169            crate::from_str(r#"{ "description": "An ambient temperature sensor" }"#),
1170            Ok((
1171                Property {
1172                    description: Some("An ambient temperature sensor"),
1173                },
1174                50
1175            ))
1176        );
1177
1178        assert_eq!(
1179            crate::from_str(r#"{ "description": null }"#),
1180            Ok((Property { description: None }, 23))
1181        );
1182
1183        assert_eq!(
1184            crate::from_str(r#"{}"#),
1185            Ok((Property { description: None }, 2))
1186        );
1187    }
1188
1189    #[test]
1190    fn struct_u8() {
1191        #[derive(Debug, Deserialize, PartialEq)]
1192        struct Temperature {
1193            temperature: u8,
1194        }
1195
1196        assert_eq!(
1197            crate::from_str(r#"{ "temperature": 20 }"#),
1198            Ok((Temperature { temperature: 20 }, 21))
1199        );
1200
1201        assert_eq!(
1202            crate::from_str(r#"{ "temperature": 0 }"#),
1203            Ok((Temperature { temperature: 0 }, 20))
1204        );
1205
1206        // out of range
1207        assert!(crate::from_str::<Temperature>(r#"{ "temperature": 256 }"#).is_err());
1208        assert!(crate::from_str::<Temperature>(r#"{ "temperature": -1 }"#).is_err());
1209    }
1210
1211    #[test]
1212    fn test_unit() {
1213        assert_eq!(crate::from_str::<()>(r#"null"#), Ok(((), 4)));
1214    }
1215
1216    #[test]
1217    fn newtype_struct() {
1218        #[derive(Deserialize, Debug, PartialEq)]
1219        struct A(pub u32);
1220
1221        assert_eq!(crate::from_str::<A>(r#"54"#), Ok((A(54), 2)));
1222    }
1223
1224    #[test]
1225    fn test_newtype_variant() {
1226        #[derive(Deserialize, Debug, PartialEq)]
1227        enum A {
1228            A(u32),
1229        }
1230        let a = A::A(54);
1231        let x = crate::from_str::<A>(r#"{"A":54}"#);
1232        assert_eq!(x, Ok((a, 8)));
1233    }
1234
1235    #[test]
1236    fn test_struct_variant() {
1237        #[derive(Deserialize, Debug, PartialEq)]
1238        enum A {
1239            A { x: u32, y: u16 },
1240        }
1241        let a = A::A { x: 54, y: 720 };
1242        let x = crate::from_str::<A>(r#"{"A": {"x":54,"y":720 } }"#);
1243        assert_eq!(x, Ok((a, 25)));
1244    }
1245
1246    #[test]
1247    #[cfg(not(feature = "custom-error-messages"))]
1248    fn struct_tuple() {
1249        #[derive(Debug, Deserialize, PartialEq)]
1250        struct Xy(i8, i8);
1251
1252        assert_eq!(crate::from_str(r#"[10, 20]"#), Ok((Xy(10, 20), 8)));
1253        assert_eq!(crate::from_str(r#"[10, -20]"#), Ok((Xy(10, -20), 9)));
1254
1255        // wrong number of args
1256        assert_eq!(
1257            crate::from_str::<Xy>(r#"[10]"#),
1258            Err(crate::de::Error::CustomError)
1259        );
1260        assert_eq!(
1261            crate::from_str::<Xy>(r#"[10, 20, 30]"#),
1262            Err(crate::de::Error::TrailingCharacters)
1263        );
1264    }
1265
1266    #[test]
1267    #[cfg(feature = "custom-error-messages")]
1268    fn struct_tuple() {
1269        #[derive(Debug, Deserialize, PartialEq)]
1270        struct Xy(i8, i8);
1271
1272        assert_eq!(crate::from_str(r#"[10, 20]"#), Ok((Xy(10, 20), 8)));
1273        assert_eq!(crate::from_str(r#"[10, -20]"#), Ok((Xy(10, -20), 9)));
1274
1275        // wrong number of args
1276        assert_eq!(
1277            crate::from_str::<Xy>(r#"[10]"#),
1278            Err(crate::de::Error::CustomErrorWithMessage(
1279                "invalid length 1, expected tuple struct Xy with 2 elements"
1280                    .parse()
1281                    .unwrap()
1282            ))
1283        );
1284        assert_eq!(
1285            crate::from_str::<Xy>(r#"[10, 20, 30]"#),
1286            Err(crate::de::Error::TrailingCharacters)
1287        );
1288    }
1289
1290    #[test]
1291    fn struct_with_array_field() {
1292        #[derive(Debug, Deserialize, PartialEq)]
1293        struct Test {
1294            status: bool,
1295            point: [u32; 3],
1296        }
1297
1298        assert_eq!(
1299            crate::from_str(r#"{ "status": true, "point": [1, 2, 3] }"#),
1300            Ok((
1301                Test {
1302                    status: true,
1303                    point: [1, 2, 3]
1304                },
1305                38
1306            ))
1307        );
1308    }
1309
1310    #[test]
1311    fn struct_with_tuple_field() {
1312        #[derive(Debug, Deserialize, PartialEq)]
1313        struct Test {
1314            status: bool,
1315            point: (u32, u32, u32),
1316        }
1317
1318        assert_eq!(
1319            crate::from_str(r#"{ "status": true, "point": [1, 2, 3] }"#),
1320            Ok((
1321                Test {
1322                    status: true,
1323                    point: (1, 2, 3)
1324                },
1325                38
1326            ))
1327        );
1328    }
1329
1330    #[test]
1331    fn ignoring_extra_fields() {
1332        #[derive(Debug, Deserialize, PartialEq)]
1333        struct Temperature {
1334            temperature: u8,
1335        }
1336
1337        assert_eq!(
1338            crate::from_str(r#"{ "temperature": 20, "high": 80, "low": -10, "updated": true }"#),
1339            Ok((Temperature { temperature: 20 }, 62))
1340        );
1341
1342        assert_eq!(
1343            crate::from_str(
1344                r#"{ "temperature": 20, "conditions": "windy", "forecast": "cloudy" }"#
1345            ),
1346            Ok((Temperature { temperature: 20 }, 66))
1347        );
1348
1349        assert_eq!(
1350            crate::from_str(r#"{ "temperature": 20, "hourly_conditions": ["windy", "rainy"] }"#),
1351            Ok((Temperature { temperature: 20 }, 62))
1352        );
1353
1354        assert_eq!(
1355            crate::from_str(
1356                r#"{ "temperature": 20, "source": { "station": "dock", "sensors": ["front", "back"] } }"#
1357            ),
1358            Ok((Temperature { temperature: 20 }, 84))
1359        );
1360
1361        assert_eq!(
1362            crate::from_str(r#"{ "temperature": 20, "invalid": this-is-ignored }"#),
1363            Ok((Temperature { temperature: 20 }, 49))
1364        );
1365
1366        assert_eq!(
1367            crate::from_str::<Temperature>(r#"{ "temperature": 20, "broken": }"#),
1368            Err(crate::de::Error::ExpectedSomeValue)
1369        );
1370
1371        assert_eq!(
1372            crate::from_str::<Temperature>(r#"{ "temperature": 20, "broken": [ }"#),
1373            Err(crate::de::Error::ExpectedSomeValue)
1374        );
1375
1376        assert_eq!(
1377            crate::from_str::<Temperature>(r#"{ "temperature": 20, "broken": ] }"#),
1378            Err(crate::de::Error::ExpectedSomeValue)
1379        );
1380    }
1381
1382    #[test]
1383    #[cfg(feature = "custom-error-messages")]
1384    fn preserve_short_error_message() {
1385        use serde::de::Error;
1386        assert_eq!(
1387            crate::de::Error::custom("something bad happened"),
1388            crate::de::Error::CustomErrorWithMessage("something bad happened".parse().unwrap())
1389        );
1390    }
1391
1392    #[test]
1393    #[cfg(feature = "custom-error-messages")]
1394    fn truncate_error_message() {
1395        use serde::de::Error;
1396        assert_eq!(
1397            crate::de::Error::custom("0123456789012345678901234567890123456789012345678901234567890123 <- after here the message should be truncated"),
1398            crate::de::Error::CustomErrorWithMessage(
1399                "0123456789012345678901234567890123456789012345678901234567890123".parse().unwrap()
1400            )
1401        );
1402    }
1403
1404    // See https://iot.mozilla.org/wot/#thing-resource
1405    #[test]
1406    fn wot() {
1407        #[derive(Debug, Deserialize, PartialEq)]
1408        struct Thing<'a> {
1409            #[serde(borrow)]
1410            properties: Properties<'a>,
1411            #[serde(rename = "type")]
1412            ty: Type,
1413        }
1414
1415        #[derive(Debug, Deserialize, PartialEq)]
1416        struct Properties<'a> {
1417            #[serde(borrow)]
1418            temperature: Property<'a>,
1419            #[serde(borrow)]
1420            humidity: Property<'a>,
1421            #[serde(borrow)]
1422            led: Property<'a>,
1423        }
1424
1425        #[derive(Debug, Deserialize, PartialEq)]
1426        struct Property<'a> {
1427            #[serde(rename = "type")]
1428            ty: Type,
1429            unit: Option<&'a str>,
1430            #[serde(borrow)]
1431            description: Option<&'a str>,
1432            href: &'a str,
1433        }
1434
1435        assert_eq!(
1436            crate::from_str::<Thing<'_>>(
1437                r#"
1438                    {
1439                    "type": "thing",
1440                    "properties": {
1441                        "temperature": {
1442                        "type": "number",
1443                        "unit": "celsius",
1444                        "description": "An ambient temperature sensor",
1445                        "href": "/properties/temperature"
1446                        },
1447                        "humidity": {
1448                        "type": "number",
1449                        "unit": "percent",
1450                        "href": "/properties/humidity"
1451                        },
1452                        "led": {
1453                        "type": "boolean",
1454                        "description": "A red LED",
1455                        "href": "/properties/led"
1456                        }
1457                    }
1458                    }
1459                    "#
1460            ),
1461            Ok((
1462                Thing {
1463                    properties: Properties {
1464                        temperature: Property {
1465                            ty: Type::Number,
1466                            unit: Some("celsius"),
1467                            description: Some("An ambient temperature sensor"),
1468                            href: "/properties/temperature",
1469                        },
1470                        humidity: Property {
1471                            ty: Type::Number,
1472                            unit: Some("percent"),
1473                            description: None,
1474                            href: "/properties/humidity",
1475                        },
1476                        led: Property {
1477                            ty: Type::Boolean,
1478                            unit: None,
1479                            description: Some("A red LED"),
1480                            href: "/properties/led",
1481                        },
1482                    },
1483                    ty: Type::Thing,
1484                },
1485                852
1486            ))
1487        )
1488    }
1489}