Skip to main content

minicbor/
data.rs

1//! CBOR data types, tokens and tags.
2
3#[cfg(feature = "half")]
4mod token;
5
6use core::fmt;
7use core::ops::{Deref, DerefMut};
8
9#[cfg(feature = "half")]
10pub use token::Token;
11
12/// CBOR data types.
13#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
14pub enum Type {
15    Bool,
16    Null,
17    Undefined,
18    U8,
19    U16,
20    U32,
21    U64,
22    I8,
23    I16,
24    I32,
25    I64,
26    Int,
27    F16,
28    F32,
29    F64,
30    Simple,
31    Bytes,
32    BytesIndef,
33    String,
34    StringIndef,
35    Array,
36    ArrayIndef,
37    Map,
38    MapIndef,
39    Tag,
40    Break,
41    Unknown(u8)
42}
43
44impl fmt::Display for Type {
45    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
46        match self {
47            Type::Bool        => f.write_str("bool"),
48            Type::Null        => f.write_str("null"),
49            Type::Undefined   => f.write_str("undefined"),
50            Type::U8          => f.write_str("u8"),
51            Type::U16         => f.write_str("u16"),
52            Type::U32         => f.write_str("u32"),
53            Type::U64         => f.write_str("u64"),
54            Type::I8          => f.write_str("i8"),
55            Type::I16         => f.write_str("i16"),
56            Type::I32         => f.write_str("i32"),
57            Type::I64         => f.write_str("i64"),
58            Type::Int         => f.write_str("int"),
59            Type::F16         => f.write_str("f16"),
60            Type::F32         => f.write_str("f32"),
61            Type::F64         => f.write_str("f64"),
62            Type::Simple      => f.write_str("simple"),
63            Type::Bytes       => f.write_str("bytes"),
64            Type::BytesIndef  => f.write_str("indefinite bytes"),
65            Type::String      => f.write_str("string"),
66            Type::StringIndef => f.write_str("indefinite string"),
67            Type::Array       => f.write_str("array"),
68            Type::ArrayIndef  => f.write_str("indefinite array"),
69            Type::Map         => f.write_str("map"),
70            Type::MapIndef    => f.write_str("indefinite map"),
71            Type::Tag         => f.write_str("tag"),
72            Type::Break       => f.write_str("break"),
73            Type::Unknown(n)  => write!(f, "{n:#x}")
74        }
75    }
76}
77
78/// CBOR data item tag.
79///
80/// See [`IanaTag`] for currently known tag values which have been registered.
81#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
82pub struct Tag(u64);
83
84impl Tag {
85    pub const fn new(n: u64) -> Self {
86        Self(n)
87    }
88
89    pub const fn as_u64(self) -> u64 {
90        self.0
91    }
92}
93
94impl From<Tag> for u64 {
95    fn from(t: Tag) -> Self {
96        t.0
97    }
98}
99
100impl From<&Tag> for u64 {
101    fn from(t: &Tag) -> Self {
102        t.0
103    }
104}
105
106impl fmt::Display for Tag {
107    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108        self.0.fmt(f)
109    }
110}
111
112/// IANA registered tags.
113///
114/// See <https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml> for details.
115#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
116#[non_exhaustive]
117pub enum IanaTag {
118    DateTime,
119    Timestamp,
120    PosBignum,
121    NegBignum,
122    Decimal,
123    Bigfloat,
124    ToBase64Url,
125    ToBase64,
126    ToBase16,
127    Cbor,
128    Uri,
129    Base64Url,
130    Base64,
131    Regex,
132    Mime,
133    // Typed arrays (RFC 8746):
134    HomogenousArray,
135    TypedArrayU8,
136    TypedArrayU8Clamped,
137    TypedArrayU16B,
138    TypedArrayU32B,
139    TypedArrayU64B,
140    TypedArrayU16L,
141    TypedArrayU32L,
142    TypedArrayU64L,
143    TypedArrayI8,
144    TypedArrayI16B,
145    TypedArrayI32B,
146    TypedArrayI64B,
147    TypedArrayI16L,
148    TypedArrayI32L,
149    TypedArrayI64L,
150    TypedArrayF16B,
151    TypedArrayF32B,
152    TypedArrayF64B,
153    TypedArrayF128B,
154    TypedArrayF16L,
155    TypedArrayF32L,
156    TypedArrayF64L,
157    TypedArrayF128L,
158    MultiDimArrayR, // row-major order
159    MultiDimArrayC, // column-major order
160}
161
162impl IanaTag {
163    pub fn tag(self) -> Tag {
164        self.into()
165    }
166}
167
168impl TryFrom<Tag> for IanaTag {
169    type Error = UnknownTag;
170
171    fn try_from(t: Tag) -> Result<Self, Self::Error> {
172        match t.into() {
173            0x00  => Ok(Self::DateTime),
174            0x01  => Ok(Self::Timestamp),
175            0x02  => Ok(Self::PosBignum),
176            0x03  => Ok(Self::NegBignum),
177            0x04  => Ok(Self::Decimal),
178            0x05  => Ok(Self::Bigfloat),
179            0x15  => Ok(Self::ToBase64Url),
180            0x16  => Ok(Self::ToBase64),
181            0x17  => Ok(Self::ToBase16),
182            0x18  => Ok(Self::Cbor),
183            0x20  => Ok(Self::Uri),
184            0x21  => Ok(Self::Base64Url),
185            0x22  => Ok(Self::Base64),
186            0x23  => Ok(Self::Regex),
187            0x24  => Ok(Self::Mime),
188            0x28  => Ok(Self::MultiDimArrayR),
189            0x29  => Ok(Self::HomogenousArray),
190            0x40  => Ok(Self::TypedArrayU8),
191            0x41  => Ok(Self::TypedArrayU16B),
192            0x42  => Ok(Self::TypedArrayU32B),
193            0x43  => Ok(Self::TypedArrayU64B),
194            0x44  => Ok(Self::TypedArrayU8Clamped),
195            0x45  => Ok(Self::TypedArrayU16L),
196            0x46  => Ok(Self::TypedArrayU32L),
197            0x47  => Ok(Self::TypedArrayU64L),
198            0x48  => Ok(Self::TypedArrayI8),
199            0x49  => Ok(Self::TypedArrayI16B),
200            0x4a  => Ok(Self::TypedArrayI32B),
201            0x4b  => Ok(Self::TypedArrayI64B),
202            0x4d  => Ok(Self::TypedArrayI16L),
203            0x4e  => Ok(Self::TypedArrayI32L),
204            0x4f  => Ok(Self::TypedArrayI64L),
205            0x50  => Ok(Self::TypedArrayF16B),
206            0x51  => Ok(Self::TypedArrayF32B),
207            0x52  => Ok(Self::TypedArrayF64B),
208            0x53  => Ok(Self::TypedArrayF128B),
209            0x54  => Ok(Self::TypedArrayF16L),
210            0x55  => Ok(Self::TypedArrayF32L),
211            0x56  => Ok(Self::TypedArrayF64L),
212            0x57  => Ok(Self::TypedArrayF128L),
213            0x410 => Ok(Self::MultiDimArrayC),
214            _     => Err(UnknownTag(t))
215        }
216    }
217}
218
219impl From<IanaTag> for Tag {
220    fn from(t: IanaTag) -> Tag {
221        match t {
222            IanaTag::DateTime            => Tag::new(0x00),
223            IanaTag::Timestamp           => Tag::new(0x01),
224            IanaTag::PosBignum           => Tag::new(0x02),
225            IanaTag::NegBignum           => Tag::new(0x03),
226            IanaTag::Decimal             => Tag::new(0x04),
227            IanaTag::Bigfloat            => Tag::new(0x05),
228            IanaTag::ToBase64Url         => Tag::new(0x15),
229            IanaTag::ToBase64            => Tag::new(0x16),
230            IanaTag::ToBase16            => Tag::new(0x17),
231            IanaTag::Cbor                => Tag::new(0x18),
232            IanaTag::Uri                 => Tag::new(0x20),
233            IanaTag::Base64Url           => Tag::new(0x21),
234            IanaTag::Base64              => Tag::new(0x22),
235            IanaTag::Regex               => Tag::new(0x23),
236            IanaTag::Mime                => Tag::new(0x24),
237            IanaTag::MultiDimArrayR      => Tag::new(0x28),
238            IanaTag::HomogenousArray     => Tag::new(0x29),
239            IanaTag::TypedArrayU8        => Tag::new(0x40),
240            IanaTag::TypedArrayU16B      => Tag::new(0x41),
241            IanaTag::TypedArrayU32B      => Tag::new(0x42),
242            IanaTag::TypedArrayU64B      => Tag::new(0x43),
243            IanaTag::TypedArrayU8Clamped => Tag::new(0x44),
244            IanaTag::TypedArrayU16L      => Tag::new(0x45),
245            IanaTag::TypedArrayU32L      => Tag::new(0x46),
246            IanaTag::TypedArrayU64L      => Tag::new(0x47),
247            IanaTag::TypedArrayI8        => Tag::new(0x48),
248            IanaTag::TypedArrayI16B      => Tag::new(0x49),
249            IanaTag::TypedArrayI32B      => Tag::new(0x4a),
250            IanaTag::TypedArrayI64B      => Tag::new(0x4b),
251            IanaTag::TypedArrayI16L      => Tag::new(0x4d),
252            IanaTag::TypedArrayI32L      => Tag::new(0x4e),
253            IanaTag::TypedArrayI64L      => Tag::new(0x4f),
254            IanaTag::TypedArrayF16B      => Tag::new(0x50),
255            IanaTag::TypedArrayF32B      => Tag::new(0x51),
256            IanaTag::TypedArrayF64B      => Tag::new(0x52),
257            IanaTag::TypedArrayF128B     => Tag::new(0x53),
258            IanaTag::TypedArrayF16L      => Tag::new(0x54),
259            IanaTag::TypedArrayF32L      => Tag::new(0x55),
260            IanaTag::TypedArrayF64L      => Tag::new(0x56),
261            IanaTag::TypedArrayF128L     => Tag::new(0x57),
262            IanaTag::MultiDimArrayC      => Tag::new(0x410)
263        }
264    }
265}
266
267impl From<&IanaTag> for Tag {
268    fn from(t: &IanaTag) -> Tag {
269        Tag::from(*t)
270    }
271}
272
273impl From<IanaTag> for u64 {
274    fn from(t: IanaTag) -> Self {
275        Tag::from(t).into()
276    }
277}
278
279impl From<&IanaTag> for u64 {
280    fn from(t: &IanaTag) -> Self {
281        Tag::from(t).into()
282    }
283}
284
285/// Error indicating that a tag value is unknown to [`IanaTag`].
286#[derive(Debug)]
287pub struct UnknownTag(Tag);
288
289impl fmt::Display for UnknownTag {
290    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
291        write!(f, "unknown tag: {:#x}", self.0.as_u64())
292    }
293}
294
295impl core::error::Error for UnknownTag {}
296
297
298/// Statically tag a value.
299///
300/// # Example
301///
302/// ```
303/// use minicbor::data::{IanaTag, Tagged};
304///
305/// let input = [
306///     0xc0, 0x74, 0x32, 0x30, 0x31, 0x33, 0x2d, 0x30,
307///     0x33, 0x2d, 0x32, 0x31, 0x54, 0x32, 0x30, 0x3a,
308///     0x30, 0x34, 0x3a, 0x30, 0x30, 0x5a
309/// ];
310///
311/// let date_time: Tagged<0, &str> = minicbor::decode(&input)?;
312/// assert_eq!(date_time.tag(), IanaTag::DateTime.tag());
313/// assert_eq!(date_time.value(), &"2013-03-21T20:04:00Z");
314///
315/// # Ok::<_, Box<dyn core::error::Error>>(())
316///
317/// ```
318#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
319pub struct Tagged<const N: u64, T>(T);
320
321impl<const N: u64, T> Tagged<N, T> {
322    pub const TAG: Tag = Tag::new(N);
323
324    pub const fn new(val: T) -> Self {
325        Self(val)
326    }
327
328    pub const fn tag(&self) -> Tag {
329        Self::TAG
330    }
331
332    pub const fn value(&self) -> &T {
333        &self.0
334    }
335
336    pub fn value_mut(&mut self) -> &mut T {
337        &mut self.0
338    }
339
340    pub fn into_value(self) -> T {
341        self.0
342    }
343}
344
345impl<const N: u64, T> From<T> for Tagged<N, T> {
346    fn from(val: T) -> Self {
347        Self::new(val)
348    }
349}
350
351impl<const N: u64, T> Deref for Tagged<N, T> {
352    type Target = T;
353
354    fn deref(&self) -> &Self::Target {
355        &self.0
356    }
357}
358
359impl<const N: u64, T> DerefMut for Tagged<N, T> {
360    fn deref_mut(&mut self) -> &mut Self::Target {
361        &mut self.0
362    }
363}
364
365
366/// CBOR integer type that covers values of [-2<sup>64</sup>, 2<sup>64</sup> - 1]
367///
368/// CBOR integers keep the sign bit in the major type so there is one extra bit
369/// available for signed numbers compared to Rust's integer types. This type can
370/// be used to encode and decode the full CBOR integer range.
371#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
372pub struct Int { neg: bool, val: u64 }
373
374/// Max. CBOR integer value (2<sup>64</sup> - 1).
375pub const MAX_INT: Int = Int { neg: false, val: u64::MAX };
376
377/// Min. CBOR integer value (-2<sup>64</sup>).
378pub const MIN_INT: Int = Int { neg: true, val: u64::MAX };
379
380impl Int {
381    pub(crate) fn pos<T: Into<u64>>(val: T) -> Self {
382        Int { neg: false, val: val.into() }
383    }
384
385    pub(crate) fn neg<T: Into<u64>>(val: T) -> Self {
386        Int { neg: true, val: val.into() }
387    }
388
389    pub(crate) fn value(&self) -> u64 {
390        self.val
391    }
392
393    pub(crate) fn is_negative(&self) -> bool {
394        self.neg
395    }
396}
397
398impl fmt::Display for Int {
399    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> core::fmt::Result {
400        write!(f, "{}", i128::from(*self))
401    }
402}
403
404// Introductions:
405
406impl From<u8> for Int {
407    fn from(i: u8) -> Self {
408        Int::from(u64::from(i))
409    }
410}
411
412impl From<u16> for Int {
413    fn from(i: u16) -> Self {
414        Int::from(u64::from(i))
415    }
416}
417
418impl From<u32> for Int {
419    fn from(i: u32) -> Self {
420        Int::from(u64::from(i))
421    }
422}
423
424impl From<u64> for Int {
425    fn from(i: u64) -> Self {
426        Int::pos(i)
427    }
428}
429
430impl TryFrom<u128> for Int {
431    type Error = TryFromIntError;
432
433    fn try_from(i: u128) -> Result<Self, Self::Error> {
434        Ok(Int::from(u64::try_from(i).map_err(|_| TryFromIntError("u64"))?))
435    }
436}
437
438impl From<i8> for Int {
439    fn from(i: i8) -> Self {
440        Int::from(i64::from(i))
441    }
442}
443
444impl From<i16> for Int {
445    fn from(i: i16) -> Self {
446        Int::from(i64::from(i))
447    }
448}
449
450impl From<i32> for Int {
451    fn from(i: i32) -> Self {
452        Int::from(i64::from(i))
453    }
454}
455
456impl From<i64> for Int {
457    fn from(i: i64) -> Self {
458        if i.is_negative() {
459            Int { neg: true, val: (-1 - i) as u64 }
460        } else {
461            Int { neg: false, val: i as u64 }
462        }
463    }
464}
465
466impl TryFrom<i128> for Int {
467    type Error = TryFromIntError;
468
469    fn try_from(i: i128) -> Result<Self, Self::Error> {
470        if i.is_negative() {
471            if i < -0x1_0000_0000_0000_0000 {
472                Err(TryFromIntError("Int"))
473            } else {
474                Ok(Int { neg: true, val: (-1 - i) as u64 })
475            }
476        } else if i > 0xFFFF_FFFF_FFFF_FFFF {
477            Err(TryFromIntError("Int"))
478        } else {
479            Ok(Int { neg: false, val: i as u64 })
480        }
481    }
482}
483
484// Eliminations:
485
486impl TryFrom<Int> for u8 {
487    type Error = TryFromIntError;
488
489    fn try_from(i: Int) -> Result<Self, Self::Error> {
490        u64::try_from(i).and_then(|n| u8::try_from(n).map_err(|_| TryFromIntError("u8")))
491    }
492}
493
494impl TryFrom<Int> for u16 {
495    type Error = TryFromIntError;
496
497    fn try_from(i: Int) -> Result<Self, Self::Error> {
498        u64::try_from(i).and_then(|n| u16::try_from(n).map_err(|_| TryFromIntError("u16")))
499    }
500}
501
502impl TryFrom<Int> for u32 {
503    type Error = TryFromIntError;
504
505    fn try_from(i: Int) -> Result<Self, Self::Error> {
506        u64::try_from(i).and_then(|n| u32::try_from(n).map_err(|_| TryFromIntError("u32")))
507    }
508}
509
510impl TryFrom<Int> for u64 {
511    type Error = TryFromIntError;
512
513    fn try_from(i: Int) -> Result<Self, Self::Error> {
514        if i.neg {
515            return Err(TryFromIntError("u64"))
516        }
517        Ok(i.val)
518    }
519}
520
521impl TryFrom<Int> for u128 {
522    type Error = TryFromIntError;
523
524    fn try_from(i: Int) -> Result<Self, Self::Error> {
525        if i.neg {
526            return Err(TryFromIntError("u128"))
527        }
528        Ok(u128::from(i.val))
529    }
530}
531
532impl TryFrom<Int> for i8 {
533    type Error = TryFromIntError;
534
535    fn try_from(i: Int) -> Result<Self, Self::Error> {
536        i64::try_from(i).and_then(|n| i8::try_from(n).map_err(|_| TryFromIntError("i8")))
537    }
538}
539
540impl TryFrom<Int> for i16 {
541    type Error = TryFromIntError;
542
543    fn try_from(i: Int) -> Result<Self, Self::Error> {
544        i64::try_from(i).and_then(|n| i16::try_from(n).map_err(|_| TryFromIntError("i16")))
545    }
546}
547
548impl TryFrom<Int> for i32 {
549    type Error = TryFromIntError;
550
551    fn try_from(i: Int) -> Result<Self, Self::Error> {
552        i64::try_from(i).and_then(|n| i32::try_from(n).map_err(|_| TryFromIntError("i32")))
553    }
554}
555
556impl TryFrom<Int> for i64 {
557    type Error = TryFromIntError;
558
559    fn try_from(i: Int) -> Result<Self, Self::Error> {
560        let j = i64::try_from(i.val).map_err(|_| TryFromIntError("i64"))?;
561        Ok(if i.neg { -1 - j } else { j })
562    }
563}
564
565impl From<Int> for i128 {
566    fn from(i: Int) -> Self {
567        let j = i128::from(i.val);
568        if i.neg { -1 - j } else { j }
569    }
570}
571
572/// Error when conversion of a CBOR [`Int`] to another type failed.
573#[derive(Debug)]
574pub struct TryFromIntError(&'static str);
575
576impl fmt::Display for TryFromIntError {
577    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
578        write!(f, "value out of {} range", self.0)
579    }
580}
581
582impl core::error::Error for TryFromIntError {}