1use super::{cons::*, IntoRawBits64};
15use core::num::NonZeroU64;
16
17pub const CELL_MARKER_BITS: u64 = SIGN_BIT | NAN_BITS;
19
20pub const CELL_MARKER_MASK: u64 = SIGN_BIT | NAN_BITS;
22
23pub const CELL_TAG_BITS: u64 = 0x0007000000000000;
25
26#[derive(Copy, Clone)]
33#[repr(u64)]
34pub enum CellTag {
35 Tag1 = 0x0001000000000000,
39
40 Tag2 = 0x0002000000000000,
42
43 Tag3 = 0x0003000000000000,
45
46 Tag4 = 0x0004000000000000,
48
49 Tag5 = 0x0005000000000000,
51
52 Tag6 = 0x0006000000000000,
54
55 Tag7 = 0x0007000000000000,
57}
58
59impl TryFrom<u64> for CellTag {
60 type Error = (); fn try_from(value: u64) -> Result<Self, Self::Error> {
62 Ok(match value {
63 0x0001000000000000 => Self::Tag1,
64 0x0002000000000000 => Self::Tag2,
65 0x0003000000000000 => Self::Tag3,
66 0x0004000000000000 => Self::Tag4,
67 0x0005000000000000 => Self::Tag5,
68 0x0006000000000000 => Self::Tag6,
69 0x0007000000000000 => Self::Tag7,
70 _ => return Err(())
71 })
72 }
73}
74
75pub const CELL_TAG_1: u64 = CellTag::Tag1 as u64;
79
80pub const CELL_TAG_2: u64 = CellTag::Tag2 as u64;
82
83pub const CELL_TAG_3: u64 = CellTag::Tag3 as u64;
85
86pub const CELL_TAG_4: u64 = CellTag::Tag4 as u64;
88
89pub const CELL_TAG_5: u64 = CellTag::Tag5 as u64;
91
92pub const CELL_TAG_6: u64 = CellTag::Tag6 as u64;
94
95pub const CELL_TAG_7: u64 = CellTag::Tag7 as u64;
97
98pub const CELL_DATA_BITS: u64 = !(CELL_MARKER_BITS | CELL_TAG_BITS);
100
101#[test]
103pub fn test_cell_bits() {
104 assert!(CELL_MARKER_BITS != CELL_TAG_BITS);
105 assert!(CELL_MARKER_BITS != CELL_DATA_BITS);
106 assert!(CELL_TAG_BITS != CELL_DATA_BITS);
107 assert!(CELL_MARKER_BITS & CELL_TAG_BITS & CELL_DATA_BITS == 0);
108 assert!(CELL_MARKER_BITS | CELL_TAG_BITS | CELL_DATA_BITS == u64::MAX);
109 assert!(CELL_MARKER_BITS ^ CELL_TAG_BITS ^ CELL_DATA_BITS == u64::MAX);
110}
111
112#[test]
113#[cfg(feature = "std")]
114pub fn test_ptr_roundtrip() {
115 let val: &'static [u8] = &[0,1,2,3,4,5,6,7,8,9];
116 let ptr_before = val.as_ptr() as *const ();
117 let nan = from_tag_and_pointer(CellTag::Tag5, ptr_before).unwrap();
118 let ptr_after = unwrap_cell_rawptr(nan).unwrap();
119 assert!(ptr_before == ptr_after, "Before {ptr_before:?} == After {ptr_after:?}")
120}
121
122#[inline(always)]
124pub fn is_cell(value: impl IntoRawBits64) -> bool {
125 (value.as_raw_bits_64() & CELL_MARKER_BITS) == CELL_MARKER_BITS
126}
127
128#[inline(always)]
130pub fn is_not_cell(value: impl IntoRawBits64) -> bool {
131 (value.as_raw_bits_64() & CELL_MARKER_BITS) != CELL_MARKER_BITS
132}
133
134#[inline(always)]
136pub fn unwrap_tag_bits_unchecked(value: impl IntoRawBits64) -> u64 {
137 value.as_raw_bits_64() & CELL_TAG_BITS
138}
139
140#[inline(always)]
142pub fn unwrap_tag_bits(value: impl IntoRawBits64) -> Option<u64> {
143 match is_cell(value) {
144 true => Some(value.as_raw_bits_64() & CELL_TAG_BITS),
145 false => None
146 }
147}
148
149#[inline(always)]
151pub fn unwrap_tag(value: impl IntoRawBits64) -> Option<CellTag> {
152 match is_cell(value) {
153 true => CellTag::try_from(value.as_raw_bits_64() & CELL_TAG_BITS).ok(),
154 false => None
155 }
156}
157
158#[inline(always)]
160pub fn unwrap_cell_unchecked(value: impl IntoRawBits64) -> u64 {
161 value.as_raw_bits_64() & CELL_DATA_BITS
162}
163
164#[inline(always)]
166pub fn unwrap_cell(value: impl IntoRawBits64) -> Option<u64> {
167 match is_cell(value) {
168 true => Some(unwrap_cell_unchecked(value)),
169 false => None
170 }
171}
172
173#[inline(always)]
175pub fn unwrap_cell_nonzero(value: impl IntoRawBits64) -> Option<NonZeroU64> {
176 match is_cell(value) {
177 true => NonZeroU64::new(unwrap_cell_unchecked(value)),
178 false => None
179 }
180}
181
182#[inline(always)]
187pub fn unwrap_cell_rawptr(value: impl IntoRawBits64) -> Option<*const ()> {
188 match is_cell(value) {
189 true => Some(unwrap_cell_unchecked(value) as *const ()),
190 false => None
191 }
192}
193
194pub fn from_tag_and_pointer(tag: CellTag, ptr: *const ()) -> Option<u64> {
209 from_tag_and_data(tag, ptr as u64)
210}
211
212pub fn from_tag_and_data(tag: CellTag, data: u64) -> Option<u64> {
213 let vtag = (tag as u64) & CELL_TAG_BITS;
214 let vdata = data & CELL_DATA_BITS;
215 if vtag != tag as u64 {return None}
216 if vdata != data {return None}
217 Some(CELL_MARKER_BITS | vtag | vdata)
218}