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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//! Contains OCaml types and conversion functions from runtime representations.
use crate::tag::Tag;

/// OCaml `value` type
pub type Value = isize;

/// OCaml's integer type
pub type Intnat = isize;

/// OCaml's unsigned integer type
pub type Uintnat = usize;

/// OCaml's size type
pub type Size = Uintnat;
pub type Color = Uintnat;
pub type Mark = Uintnat;

/// An OCaml heap-allocated block header. **NB**: this is currently unimplemented.
///
/// Structure of the header:
///
/// For 16-bit and 32-bit architectures:
///
///```text
///      +--------+-------+-----+
///      | wosize | color | tag |
///      +--------+-------+-----+
/// bits  31    10 9     8 7   0
///```
///
/// For 64-bit architectures:
///
///```text
///      +--------+-------+-----+
///      | wosize | color | tag |
///      +--------+-------+-----+
/// bits  63    10 9     8 7   0
///```
///
pub type Header = Uintnat;

/// #ifdef ARCH_BIG_ENDIAN
/// #define Tag_val(val) (((unsigned char *) (val)) [-1])
/// #else
/// #define Tag_val(val) (((unsigned char *) (val)) [-sizeof(value)])
/// #endif
#[cfg(target_endian = "big")]
#[inline]
pub const unsafe fn tag_val(val: Value) -> Tag {
    *(val as *const u8).offset(-1)
}

#[cfg(target_endian = "little")]
#[inline]
pub unsafe fn tag_val(val: Value) -> Tag {
    *(val as *const u8).offset(-(core::mem::size_of::<Value>() as isize))
}

#[inline]
pub unsafe fn hd_val(val: Value) -> Header {
    *(val as *const Header).offset(-1)
}

#[inline]
pub unsafe fn wosize_val(val: Value) -> Size {
    hd_val(val) >> 10
}

/// `(((intnat)(x) << 1) + 1)`
pub const fn val_int(i: isize) -> Value {
    ((i as isize) << 1) + 1
}

pub const fn int_val(val: Value) -> isize {
    ((val as usize) >> 1) as isize
}

pub fn is_block(v: Value) -> bool {
    (v & 1) == 0
}

pub fn is_long(v: Value) -> bool {
    (v & 1) != 0
}

// #define Max_long (((intnat)1 << (8 * sizeof(value) - 2)) - 1)
// #define Min_long (-((intnat)1 << (8 * sizeof(value) - 2)))

/// Extract a field from an OCaml value
///
/// # Safety
///
/// This function does no bounds checking or validation of the OCaml values
pub unsafe fn field(block: Value, index: usize) -> *mut Value {
    (block as *mut Value).add(index)
}

#[doc(hidden)]
pub unsafe fn as_slice<'a>(value: Value) -> &'a [Value] {
    ::core::slice::from_raw_parts((value as *const Value).offset(-1), wosize_val(value) + 1)
}

/// The OCaml `()` (`unit`) value
pub const UNIT: Value = val_int(0);

/// Empty list value
pub const EMPTY_LIST: Value = val_int(0);

/// The OCaml `true` value
pub const TRUE: Value = val_int(1);

/// OCaml `false` value
pub const FALSE: Value = val_int(0);

/// Pointer to the first byte
#[inline]
pub const unsafe fn bp_val(val: Value) -> *const u8 {
    val as *const u8
}

/// Extracts a machine `ptr` to the bytes making up an OCaml `string`
#[inline]
pub const unsafe fn string_val(val: Value) -> *mut u8 {
    val as *mut u8
}

extern "C" {
    /// Returns size of the string in `value` in bytes
    pub fn caml_string_length(value: Value) -> Size;
    pub fn caml_array_length(value: Value) -> Size;
    pub fn caml_hash_variant(tag: *const u8) -> Value;
    pub fn caml_get_public_method(obj: Value, tag: Value) -> Value;
}