1#![allow(clippy::missing_transmute_annotations)]
2
3use std::{num::NonZeroU8, os::raw::c_void, ptr::NonNull, slice};
4
5#[cfg(feature = "atom_size_128")]
6type RawTaggedValue = u128;
7#[cfg(any(
8 target_pointer_width = "32",
9 target_pointer_width = "16",
10 feature = "atom_size_64"
11))]
12type RawTaggedValue = u64;
13#[cfg(not(any(
14 target_pointer_width = "32",
15 target_pointer_width = "16",
16 feature = "atom_size_64",
17 feature = "atom_size_128"
18)))]
19type RawTaggedValue = usize;
20
21#[cfg(feature = "atom_size_128")]
22type RawTaggedNonZeroValue = std::num::NonZeroU128;
23#[cfg(any(
24 target_pointer_width = "32",
25 target_pointer_width = "16",
26 feature = "atom_size_64"
27))]
28type RawTaggedNonZeroValue = std::num::NonZeroU64;
29#[cfg(not(any(
30 target_pointer_width = "32",
31 target_pointer_width = "16",
32 feature = "atom_size_64",
33 feature = "atom_size_128"
34)))]
35type RawTaggedNonZeroValue = std::ptr::NonNull<()>;
36
37pub(crate) const MAX_INLINE_LEN: usize = std::mem::size_of::<TaggedValue>() - 1;
38
39#[derive(Copy, Clone, Debug, PartialEq, Eq)]
40#[repr(transparent)]
41pub(crate) struct TaggedValue {
42 value: RawTaggedNonZeroValue,
43}
44
45impl TaggedValue {
46 #[inline(always)]
47 pub fn new_ptr<T>(value: NonNull<T>) -> Self {
48 #[cfg(any(
49 target_pointer_width = "32",
50 target_pointer_width = "16",
51 feature = "atom_size_64",
52 feature = "atom_size_128"
53 ))]
54 unsafe {
55 let value: std::num::NonZeroUsize = std::mem::transmute(value);
56 Self {
57 value: RawTaggedNonZeroValue::new_unchecked(value.get() as _),
58 }
59 }
60
61 #[cfg(not(any(
62 target_pointer_width = "32",
63 target_pointer_width = "16",
64 feature = "atom_size_64",
65 feature = "atom_size_128"
66 )))]
67 {
68 Self {
69 value: value.cast(),
70 }
71 }
72 }
73
74 #[inline(always)]
75 pub const fn new_tag(value: NonZeroU8) -> Self {
76 let value = value.get() as RawTaggedValue;
77 Self {
78 value: unsafe { std::mem::transmute(value) },
79 }
80 }
81
82 #[inline(always)]
83 pub fn hash(&self) -> u64 {
84 self.get_value() as _
85 }
86
87 #[inline(always)]
88 pub fn get_ptr(&self) -> *const c_void {
89 #[cfg(any(
90 target_pointer_width = "32",
91 target_pointer_width = "16",
92 feature = "atom_size_64",
93 feature = "atom_size_128"
94 ))]
95 {
96 self.value.get() as usize as _
97 }
98 #[cfg(not(any(
99 target_pointer_width = "32",
100 target_pointer_width = "16",
101 feature = "atom_size_64",
102 feature = "atom_size_128"
103 )))]
104 unsafe {
105 std::mem::transmute(Some(self.value))
106 }
107 }
108
109 #[inline(always)]
110 fn get_value(&self) -> RawTaggedValue {
111 unsafe { std::mem::transmute(Some(self.value)) }
112 }
113
114 #[inline(always)]
115 pub fn tag(&self) -> u8 {
116 (self.get_value() & 0xff) as u8
117 }
118
119 pub fn data(&self) -> &[u8] {
120 let x: *const _ = &self.value;
121 let mut data = x as *const u8;
122 if cfg!(target_endian = "little") {
125 unsafe {
126 data = data.offset(1);
127 }
128 }
129 let len = std::mem::size_of::<TaggedValue>() - 1;
130 unsafe { slice::from_raw_parts(data, len) }
131 }
132
133 pub const unsafe fn data_mut(&mut self) -> &mut [u8] {
138 let x: *mut _ = &mut self.value;
139 let mut data = x as *mut u8;
140 if cfg!(target_endian = "little") {
143 data = data.offset(1);
144 }
145 let len = std::mem::size_of::<TaggedValue>() - 1;
146 slice::from_raw_parts_mut(data, len)
147 }
148}