1use std::cmp::Ordering;
9use std::fmt::{self, Write as _};
10use std::rc::Rc;
11
12use crate::ffi::Slice;
13
14pub type Slot = u64;
15
16#[derive(Clone, Copy, Debug, PartialEq, Eq)]
18#[repr(u8)]
19pub enum TypeKind {
20 Int,
21 Float,
22 Bool,
23 String,
24 List,
26 Struct,
28}
29
30#[derive(Debug)]
33#[repr(C)]
34pub struct TypeDesc {
35 kind: TypeKind,
36 children: Slice<&'static TypeDesc>,
37}
38
39pub use crate::symbols::{BOOL, FLOAT, INT, STRING};
40
41impl TypeKind {
42 #[must_use]
43 pub const fn code(self) -> u8 {
44 self as u8
45 }
46}
47
48impl TypeDesc {
49 pub const KIND_OFFSET: usize = std::mem::offset_of!(Self, kind);
51 pub const CHILDREN_OFFSET: usize = std::mem::offset_of!(Self, children);
52
53 pub(crate) const fn scalar(kind: TypeKind) -> Self {
54 Self {
55 kind,
56 children: Slice::EMPTY,
57 }
58 }
59
60 #[must_use]
61 pub const fn list(element: &'static [&'static Self; 1]) -> Self {
62 Self {
63 kind: TypeKind::List,
64 children: Slice::new(element),
65 }
66 }
67
68 #[must_use]
69 pub const fn structure(fields: &'static [&'static Self]) -> Self {
70 Self {
71 kind: TypeKind::Struct,
72 children: Slice::new(fields),
73 }
74 }
75
76 #[must_use]
77 pub fn kind(&self) -> TypeKind {
78 self.kind
79 }
80
81 #[must_use]
83 pub fn children(&self) -> &'static [&'static Self] {
84 self.children.items()
85 }
86
87 fn element(&self) -> &'static Self {
88 self.children()[0]
89 }
90
91 fn is_object(&self) -> bool {
92 matches!(
93 self.kind,
94 TypeKind::String | TypeKind::List | TypeKind::Struct
95 )
96 }
97}
98
99pub(crate) struct StringObject(pub Box<str>);
100
101pub(crate) struct ListObject {
102 pub element: &'static TypeDesc,
103 pub items: Vec<Slot>,
104}
105
106pub(crate) struct StructObject {
107 pub ty: &'static TypeDesc,
108 pub fields: Box<[Slot]>,
109}
110
111impl Clone for ListObject {
112 fn clone(&self) -> Self {
113 for item in &self.items {
114 retain(*item, self.element);
115 }
116 Self {
117 element: self.element,
118 items: self.items.clone(),
119 }
120 }
121}
122
123impl Drop for ListObject {
124 fn drop(&mut self) {
125 for item in &self.items {
126 release(*item, self.element);
127 }
128 }
129}
130
131impl Clone for StructObject {
132 fn clone(&self) -> Self {
133 for (field, ty) in self.fields.iter().zip(self.ty.children()) {
134 retain(*field, ty);
135 }
136 Self {
137 ty: self.ty,
138 fields: self.fields.clone(),
139 }
140 }
141}
142
143impl Drop for StructObject {
144 fn drop(&mut self) {
145 for (field, ty) in self.fields.iter().zip(self.ty.children()) {
146 release(*field, ty);
147 }
148 }
149}
150
151pub(crate) static LIST_OF_STRINGS: TypeDesc = TypeDesc::list(&[&STRING]);
153
154pub(crate) fn strings_slot(texts: Vec<String>) -> Slot {
156 list_slot(
157 &LIST_OF_STRINGS,
158 texts.into_iter().map(string_slot).collect(),
159 )
160}
161
162pub(crate) fn list_slot(ty: &TypeDesc, items: Vec<Slot>) -> Slot {
164 into_slot(Rc::new(ListObject {
165 element: ty.element(),
166 items,
167 }))
168}
169
170pub(crate) fn into_slot<T>(object: Rc<T>) -> Slot {
172 Rc::into_raw(object).expose_provenance() as Slot
173}
174
175fn pointer<T>(slot: Slot) -> *const T {
176 let address = usize::try_from(slot).expect("Nifty only runs on 64-bit systems");
177 std::ptr::with_exposed_provenance(address)
178}
179
180pub(crate) unsafe fn from_slot<T>(slot: Slot) -> Rc<T> {
185 unsafe { Rc::from_raw(pointer(slot)) }
187}
188
189pub(crate) unsafe fn borrow<'a, T>(slot: Slot) -> &'a T {
194 unsafe { &*pointer::<T>(slot) }
196}
197
198pub(crate) fn retain(slot: Slot, ty: &TypeDesc) {
200 if slot == 0 || !ty.is_object() {
201 return;
202 }
203 unsafe {
206 match ty.kind() {
207 TypeKind::String => Rc::increment_strong_count(pointer::<StringObject>(slot)),
208 TypeKind::List => Rc::increment_strong_count(pointer::<ListObject>(slot)),
209 TypeKind::Struct => Rc::increment_strong_count(pointer::<StructObject>(slot)),
210 TypeKind::Int | TypeKind::Float | TypeKind::Bool => {}
211 }
212 }
213}
214
215pub(crate) fn release(slot: Slot, ty: &TypeDesc) {
217 if slot == 0 || !ty.is_object() {
218 return;
219 }
220 unsafe {
222 match ty.kind() {
223 TypeKind::String => Rc::decrement_strong_count(pointer::<StringObject>(slot)),
224 TypeKind::List => Rc::decrement_strong_count(pointer::<ListObject>(slot)),
225 TypeKind::Struct => Rc::decrement_strong_count(pointer::<StructObject>(slot)),
226 TypeKind::Int | TypeKind::Float | TypeKind::Bool => {}
227 }
228 }
229}
230
231pub(crate) fn string_slot(text: impl Into<Box<str>>) -> Slot {
232 into_slot(Rc::new(StringObject(text.into())))
233}
234
235pub(crate) fn as_str<'a>(slot: Slot) -> &'a str {
237 unsafe { &borrow::<StringObject>(slot).0 }
239}
240
241pub(crate) fn as_list<'a>(slot: Slot) -> &'a ListObject {
242 unsafe { borrow(slot) }
244}
245
246pub(crate) fn as_struct<'a>(slot: Slot) -> &'a StructObject {
247 unsafe { borrow(slot) }
249}
250
251pub(crate) fn list_mut(place: &mut Slot) -> &mut ListObject {
253 unique::<ListObject>(place)
254}
255
256pub(crate) fn struct_mut(place: &mut Slot) -> &mut StructObject {
257 unique::<StructObject>(place)
258}
259
260fn unique<T: Clone>(place: &mut Slot) -> &mut T {
261 let mut object = unsafe { from_slot::<T>(*place) };
263 Rc::make_mut(&mut object);
264 *place = into_slot(object);
265 unsafe { &mut *pointer::<T>(*place).cast_mut() }
267}
268
269pub(crate) fn int(slot: Slot) -> i64 {
270 i64::from_ne_bytes(slot.to_ne_bytes())
271}
272
273pub(crate) fn int_slot(value: i64) -> Slot {
274 Slot::from_ne_bytes(value.to_ne_bytes())
275}
276
277pub(crate) fn equal(a: Slot, b: Slot, ty: &TypeDesc) -> bool {
279 match ty.kind() {
280 TypeKind::Int | TypeKind::Bool => a == b,
281 TypeKind::Float => {
283 f64::from_bits(a).partial_cmp(&f64::from_bits(b)) == Some(Ordering::Equal)
284 }
285 TypeKind::String => as_str(a) == as_str(b),
286 TypeKind::List => {
287 let (a, b) = (as_list(a), as_list(b));
288 a.items.len() == b.items.len()
289 && a.items
290 .iter()
291 .zip(&b.items)
292 .all(|(a, b)| equal(*a, *b, ty.element()))
293 }
294 TypeKind::Struct => {
295 let (a, b) = (as_struct(a), as_struct(b));
296 a.fields
297 .iter()
298 .zip(b.fields.iter())
299 .zip(ty.children())
300 .all(|((a, b), ty)| equal(*a, *b, ty))
301 }
302 }
303}
304
305pub(crate) fn write(text: &mut String, slot: Slot, ty: &TypeDesc) {
307 let written = match ty.kind() {
308 TypeKind::Int => write!(text, "{}", int(slot)),
309 TypeKind::Float => write!(text, "{}", f64::from_bits(slot)),
310 TypeKind::Bool => write!(text, "{}", slot != 0),
311 TypeKind::String => text.write_str(as_str(slot)),
312 TypeKind::List => {
313 let list = as_list(slot);
314 write_items(text, list.items.iter().map(|item| (*item, list.element)));
315 Ok(())
316 }
317 TypeKind::Struct => {
318 let object = as_struct(slot);
319 let fields = object.fields.iter().copied();
320 write_items(text, fields.zip(object.ty.children().iter().copied()));
321 Ok(())
322 }
323 };
324 written.expect("writing to a String cannot fail");
325}
326
327fn write_items(text: &mut String, items: impl Iterator<Item = (Slot, &'static TypeDesc)>) {
328 text.push('[');
329 for (index, (item, ty)) in items.enumerate() {
330 if index > 0 {
331 text.push_str(", ");
332 }
333 write(text, item, ty);
334 }
335 text.push(']');
336}
337
338pub(crate) struct Value {
340 slot: Slot,
341 ty: &'static TypeDesc,
342}
343
344impl Value {
345 pub(crate) fn owned(slot: Slot, ty: &'static TypeDesc) -> Self {
347 Self { slot, ty }
348 }
349
350 pub(crate) fn slot(&self) -> Slot {
351 self.slot
352 }
353}
354
355impl Clone for Value {
356 fn clone(&self) -> Self {
357 retain(self.slot, self.ty);
358 Self {
359 slot: self.slot,
360 ty: self.ty,
361 }
362 }
363}
364
365impl Drop for Value {
366 fn drop(&mut self) {
367 release(self.slot, self.ty);
368 }
369}
370
371impl fmt::Debug for Value {
372 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
373 let mut text = String::new();
374 write(&mut text, self.slot, self.ty);
375 f.debug_tuple("Value").field(&text).finish()
376 }
377}
378
379#[cfg(test)]
380mod tests;