1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
//! CBOR helper types for encoding and decoding.
use std::convert::TryFrom;

use crate::error::UnexpectedCode;
use libipld_core::ipld::Ipld;

/// Represents a major "byte". This includes both the major bits and the additional info.
#[repr(transparent)]
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Major(u8);

/// The constant TRUE.
pub const FALSE: Major = Major::new(MajorKind::Other, 20);
/// The constant FALSE.
pub const TRUE: Major = Major::new(MajorKind::Other, 21);
/// The constant NULL.
pub const NULL: Major = Major::new(MajorKind::Other, 22);
/// The major "byte" indicating that a 16 bit float follows.
pub const F16: Major = Major::new(MajorKind::Other, 25);
/// The major "byte" indicating that a 32 bit float follows.
pub const F32: Major = Major::new(MajorKind::Other, 26);
/// The major "byte" indicating that a 64 bit float follows.
pub const F64: Major = Major::new(MajorKind::Other, 27);

impl Major {
    const fn new(kind: MajorKind, info: u8) -> Self {
        Major(((kind as u8) << 5) | info)
    }

    /// Returns the major type.
    #[inline(always)]
    pub const fn kind(self) -> MajorKind {
        // This is a 3 bit value, so value 0-7 are covered.
        unsafe { std::mem::transmute(self.0 >> 5) }
    }

    /// Returns the additional info.
    #[inline(always)]
    pub const fn info(self) -> u8 {
        self.0 & 0x1f
    }

    /// Interprets the additioanl info as a number of additional bytes that should be consumed.
    #[inline(always)]
    #[allow(clippy::len_without_is_empty)]
    pub const fn len(self) -> u8 {
        // All major types follow the same rules for "additioanl bytes".
        // 24 -> 1, 25 -> 2, 26 -> 4, 27 -> 8
        match self.info() {
            info @ 24..=27 => 1 << (info - 24),
            _ => 0,
        }
    }
}

impl From<Major> for u8 {
    fn from(m: Major) -> u8 {
        m.0
    }
}

// This is the core of the validation logic. Every major type passes through here giving us a chance
// to determine if it's something we allow.
impl TryFrom<u8> for Major {
    type Error = UnexpectedCode;
    fn try_from(value: u8) -> Result<Self, Self::Error> {
        // We don't allow any major types with additional info 28-31 inclusive.
        // Or the bitmask 0b00011100 = 28.
        if value & 28 == 28 {
            return Err(UnexpectedCode::new::<Ipld>(value));
        } else if (value >> 5) == MajorKind::Other as u8 {
            match value & 0x1f {
                // False, True, Null. TODO: Allow undefined?
                20 | 21 | 22 => (),
                // Floats. TODO: forbid f16 & f32?
                25 | 26 | 27 => (),
                // Everything is forbidden.
                _ => {
                    return Err(UnexpectedCode::new::<Ipld>(value));
                }
            }
        }
        Ok(Major(value))
    }
}

/// The type
#[repr(u8)]
#[derive(Clone, Copy, Eq, PartialEq)]
#[allow(dead_code)]
pub enum MajorKind {
    /// Non-negative integer (major type 0).
    UnsignedInt = 0,
    /// Negative integer (major type 1).
    NegativeInt = 1,
    /// Byte string (major type 2).
    ByteString = 2,
    /// Unicode text string (major type 3).
    TextString = 3,
    /// Array (major type 4).
    Array = 4,
    /// Map (major type 5).
    Map = 5,
    /// Tag (major type 6).
    Tag = 6,
    /// Other (major type 7).
    Other = 7,
}