Low Level

Structure

  • 1 bit: s sign
  • 11 bits: x exponent
  • 52 bits: v fraction

NaN and Infinities

When exponent x is 0b_111_1111_1111.

Three special values:

  • Infinity: 0x7FF0_0000_0000_0000,
  • Neg. Infinity: 0xFFF0_0000_0000_0000,
  • NaN: 0x7FF8_0000_0000_0000.

Special Tags

Format:

s111_1111_1111_vvvv
vvvv_vvvv_vvvv_vvvv
vvvv_vvvv_vvvv_vvvv
vvvv_vvvv_vvvv_vvvv
  • s111_1111_1111_..._vv00 non-finite numbers, primitives and short string (scalars)
  • s111_1111_1111_..._vv10 reference
  • s111_1111_1111_..._vvv1 short bigint

Non-Finite Numbers, Primitives, and Short Strings (scalars)

s111_1111_1111...vvvv_vv00

Cap.States
....0000_000044non-finite3
....0001_000044boolean2
0...0010_000044undefined1
0...0011_000044null1
0...0000_100044empty string1
0...0001_1000441x162^16
0...0010_1000442x162^32
0...0100_1000444x72^28
0...0101_1000445x72^35
0...0110_1000446x72^42
0........0100483x162^48
0........1100488x62^48
1.........100497x72^49

Reference

s111_1111_1111_tttt_....10

  • s is static,
  • tttt is type.

Examples

#[repr(transparent)]
pub struct Any(u64);

const NUMBER_TYPE    : u32 = 0x0;
const BOOLEAN_TYPE   : u32 = 0x1;
const UNDEFINED_TYPE : u32 = 0x2;
const OBJECT_TYPE    : u32 = 0x3;
const STRING_TYPE    : u32 = 0x4;
const BIGINT_TYPE    : u32 = 0x5;
const FUNCTION_TYPE  : u32 = 0x6;

//

const EXP          : u64 = 0x7FF0_0000_0000_0000;

// TAG 8:

const TAG8         : u64 = 0x7FF0_0000_0000_00FF;

const NON_FINITE   : u64 = 0x7FF0_0000_0000_0000;

const INFINITY     : u64 = 0x7FF0_0000_0000_0000;
const NEG_INFINITY : u64 = 0xFFF0_0000_0000_0000;
const NAN          : u64 = 0x7FF8_0000_0000_0000;

const BOOL         : u64 = 0x7FF0_0000_0000_0010;

const FALSE        : u64 = 0x7FF0_0000_0000_0010;
const TRUE         : u64 = 0xFFF0_0000_0000_0010;

const UNDEFINED    : u64 = 0x7FF0_0000_0000_0020;
const NULL         : u64 = 0x7FF0_0000_0000_0030;

const EMPTY_STRING : u64 = 0x7FF0_0000_0000_0008;

// TAG 2:

const TAG2         : u64 = 0x7FF0_0000_0000_0003;

const SCALAR       : u64 = 0x7FF0_0000_0000_0000;
const REF          : u64 = 0x7FF0_0000_0000_0002;

const REF_TAG      : u64 = 0xFFF0_0000_0000_0003;
const DYN_REF      : u64 = 0x7FF0_0000_0000_0002;

// TAG 1:

const SHORT_BIGINT : u64 = 0x7FF0_0000_0000_0001;

impl Any {

    pub const INFINITY: Self = Self(INFINITY);
    pub const NEG_INFINITY: Self = Self(NEG_INFINITY);
    pub const NAN: Self = Self(NAN);
    pub const FALSE: Self = Self(FALSE);
    pub const TRUE: Self = Self(TRUE);
    pub const UNDEFINED: Self = Self(UNDEFINED);
    pub const NULL: Self = Self(NULL);
    pub const EMPTY_STRING: Self = Self(EMPTY_STRING);

    pub fn is_finite(&self) -> bool {
        (self.0 & EXP) != EXP
    }

    pub fn is_number(&self) -> bool {
        self.is_finite() || self.0 & TAG8 == NON_FINITE
    }

    pub fn is_bool(&self) -> bool {
        self.0 & TAG8 == BOOL
    }

    pub fn is_short_string(&self) -> bool {
        self.0 & TAG2 == SCALAR &&
        self.0 & 0xC != 0
    }

    pub fn is_ref(&self) -> bool {
        self.0 & TAG2 == REF
    }

    pub fn is_dyn_ref(&self) -> bool {
        self.0 & REF_TAG == DYN_REF
    }

    pub fn is_short_bigint(&self) -> bool {
        self.0 & SHORT_BIGINT == SHORT_BIGINT
    }

    pub fn typeof_(&self) -> u32 {
        if self.is_finite() { return NUMBER_TYPE; }
        if self.0 & 1 == 1 { return BIGINT_TYPE; }
        // reference
        if self.0 & 2 == 2 { return (self.0 >> 48) & 0xF; }
        // scalar
        if self.0 & 0xC != 0 { return STRING_TYPE; }
        (self.0 >> 4) & 0xF
    }
}

impl Clone for Any {
    fn clone(&self) -> Self {
        if self.is_dyn_ref() {
            self.add_ref();
        }
        Self(self.0)
    }
}

impl Drop for Any {
    fn drop(&mut self) {
        if self.is_dyn_ref() {
            self.release();
        }
    }
}