1use crate::k::K;
2use crate::kbox::KBox;
3use crate::symbol::Symbol;
4use crate::type_traits::*;
5use crate::{date_time_types::*, k_type::KTypeCode};
6use std::marker::PhantomData;
7use std::mem;
8use std::{fmt, ptr::NonNull};
9
10#[repr(transparent)]
22pub struct Atom<T> {
23 k: K,
24 _p: PhantomData<T>,
25}
26
27impl<T: KValue> Atom<T> {
28 #[inline]
30 pub fn value(&self) -> T {
31 unsafe { T::from_k(&self.k) }
32 }
33
34 #[inline]
36 pub fn set_value(&mut self, val: T) {
37 unsafe { *T::as_mutable(&mut self.k) = val }
38 }
39}
40
41impl<T> KObject for Atom<T> {
42 #[inline]
43 fn k_ptr(&self) -> *const K {
44 &self.k
45 }
46
47 #[inline]
48 fn k_ptr_mut(&mut self) -> *mut K {
49 &mut self.k
50 }
51}
52
53impl<T: KValue> KTyped for Atom<T> {
54 const K_TYPE: KTypeCode = T::TYPE_CODE.as_atom();
55}
56
57impl<T> private::Sealed for Atom<T> {}
58
59impl<T: KValue + fmt::Debug> fmt::Debug for Atom<T> {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 write!(f, "Atom({:?})", self.value())
62 }
63}
64
65impl<T: KValue + fmt::Display> fmt::Display for Atom<T> {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 write!(f, "{}", self.value())
68 }
69}
70
71impl<T: KValue> From<T> for KBox<Atom<T>> {
72 #[inline]
73 fn from(val: T) -> KBox<Atom<T>> {
74 KBox {
75 k: unsafe { NonNull::new_unchecked(val.into_k() as *mut K as *mut Atom<T>) },
76 }
77 }
78}
79
80macro_rules! impl_atom_from {
83 ($ty:ident) => {
84 impl From<Atom<$ty>> for $ty {
85 #[inline]
86 fn from(val: Atom<$ty>) -> $ty {
87 val.value()
88 }
89 }
90 };
91}
92
93impl_atom_from!(u8);
94impl_atom_from!(i8);
95impl_atom_from!(i16);
96impl_atom_from!(i32);
97impl_atom_from!(i64);
98
99impl_atom_from!(f32);
100impl_atom_from!(f64);
101impl_atom_from!(bool);
102
103impl_atom_from!(Second);
104impl_atom_from!(Minute);
105impl_atom_from!(Date);
106impl_atom_from!(Month);
107impl_atom_from!(Time);
108impl_atom_from!(DateTime);
109impl_atom_from!(Timestamp);
110impl_atom_from!(Timespan);
111
112impl_atom_from!(Symbol);
113
114#[cfg(feature = "uuid")]
115use uuid::Uuid;
116
117#[cfg(feature = "uuid")]
118impl_atom_from!(Uuid);
119
120impl<T: KValue> KBox<Atom<T>> {
121 #[inline]
123 pub fn new_atom(value: T) -> KBox<Atom<T>> {
124 unsafe { mem::transmute(value.into_k()) }
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 #![allow(clippy::clippy::float_cmp)]
131
132 use super::*;
133 use crate::symbol::symbol;
134 use crate::{cast, Any};
135
136 #[test]
137 fn value_returns_underlying_value() {
138 assert_eq!(KBox::new_atom(12u8).value(), 12u8);
139 assert_eq!(KBox::new_atom(13i16).value(), 13i16);
140 assert_eq!(KBox::new_atom(14i32).value(), 14i32);
141 assert_eq!(KBox::new_atom(15i64).value(), 15i64);
142 assert_eq!(KBox::new_atom(5.3f32).value(), 5.3f32);
143 assert_eq!(KBox::new_atom(true).value(), true);
144 assert_eq!(KBox::new_atom(6.4f64).value(), 6.4f64);
145
146 assert_eq!(KBox::new_atom(Second::new(5)).value(), Second::new(5));
147 assert_eq!(KBox::new_atom(Minute::new(6)).value(), Minute::new(6));
148 assert_eq!(KBox::new_atom(Date::new(2020, 2, 6)).value(), Date::new(2020, 2, 6));
149 assert_eq!(KBox::new_atom(Month::new(8)).value(), Month::new(8));
150 assert_eq!(KBox::new_atom(Time::new(9)).value(), Time::new(9));
151 assert_eq!(KBox::new_atom(DateTime::new(10.0)).value(), DateTime::new(10.0));
152 assert_eq!(KBox::new_atom(Timestamp::from_raw(11)).value(), Timestamp::from_raw(11));
153 assert_eq!(
154 KBox::new_atom(Timespan::from_nanos(12)).value(),
155 Timespan::from_nanos(12)
156 );
157
158 assert_eq!(KBox::new_atom(symbol("Foo")).value(), symbol("Foo"));
159 #[cfg(feature = "uuid")]
160 assert_eq!(
161 KBox::new_atom(uuid::Uuid::from_bytes([12u8; 16])).value(),
162 Uuid::from_bytes([12u8; 16])
163 );
164 }
165 #[test]
166 fn set_value_changes_underlying_value() {
167 assert_eq!(
168 {
169 let mut a = KBox::new_atom(11i8);
170 a.set_value(12i8);
171 a.value()
172 },
173 12i8
174 );
175 assert_eq!(
176 {
177 let mut a = KBox::new_atom(12u8);
178 a.set_value(13u8);
179 a.value()
180 },
181 13u8
182 );
183 assert_eq!(
184 {
185 let mut a = KBox::new_atom(13i16);
186 a.set_value(14i16);
187 a.value()
188 },
189 14i16
190 );
191 assert_eq!(
192 {
193 let mut a = KBox::new_atom(14i32);
194 a.set_value(15i32);
195 a.value()
196 },
197 15i32
198 );
199 assert_eq!(
200 {
201 let mut a = KBox::new_atom(15i64);
202 a.set_value(16i64);
203 a.value()
204 },
205 16i64
206 );
207 assert_eq!(
208 {
209 let mut a = KBox::new_atom(5.3f32);
210 a.set_value(4.3);
211 a.value()
212 },
213 4.3f32
214 );
215 assert_eq!(
216 {
217 let mut a = KBox::new_atom(6.4f64);
218 a.set_value(4.6f64);
219 a.value()
220 },
221 4.6f64
222 );
223 assert_eq!(
224 {
225 let mut a = KBox::new_atom(true);
226 a.set_value(false);
227 a.value()
228 },
229 false
230 );
231
232 assert_eq!(
233 {
234 let mut a = KBox::new_atom(Second::new(5));
235 a.set_value(Second::new(6));
236 a.value()
237 },
238 Second::new(6)
239 );
240 assert_eq!(
241 {
242 let mut a = KBox::new_atom(Minute::new(6));
243 a.set_value(Minute::new(7));
244 a.value()
245 },
246 Minute::new(7)
247 );
248 assert_eq!(
249 {
250 let mut a = KBox::new_atom(Date::new(2020, 2, 6));
251 a.set_value(Date::new(2020, 2, 7));
252 a.value()
253 },
254 Date::new(2020, 2, 7)
255 );
256 assert_eq!(
257 {
258 let mut a = KBox::new_atom(Month::new(8));
259 a.set_value(Month::new(9));
260 a.value()
261 },
262 Month::new(9)
263 );
264 assert_eq!(
265 {
266 let mut a = KBox::new_atom(Time::new(9));
267 a.set_value(Time::new(10));
268 a.value()
269 },
270 Time::new(10)
271 );
272 assert_eq!(
273 {
274 let mut a = KBox::new_atom(DateTime::new(10.0));
275 a.set_value(DateTime::new(11.0));
276 a.value()
277 },
278 DateTime::new(11.0)
279 );
280 assert_eq!(
281 {
282 let mut a = KBox::new_atom(Timestamp::from_raw(11));
283 a.set_value(Timestamp::from_raw(12));
284 a.value()
285 },
286 Timestamp::from_raw(12)
287 );
288 assert_eq!(
289 {
290 let mut a = KBox::new_atom(Timespan::from_nanos(12));
291 a.set_value(Timespan::from_nanos(13));
292 a.value()
293 },
294 Timespan::from_nanos(13)
295 );
296
297 assert_eq!(
298 {
299 let mut a = KBox::new_atom(symbol("Foo"));
300 a.set_value(symbol("Bar"));
301 a.value()
302 },
303 symbol("Bar")
304 );
305 assert_eq!(
306 {
307 let mut a = KBox::new_atom(Uuid::from_u128(13));
308 a.set_value(Uuid::from_u128(14));
309 a.value()
310 },
311 Uuid::from_u128(14)
312 );
313 }
314 #[test]
315 fn atoms_round_trip_to_any() {
316 assert_eq!(cast!(KBox::<Any>::from(KBox::new_atom(12u8)); Atom<u8>).value(), 12u8);
317 assert_eq!(
318 cast!(KBox::<Any>::from(KBox::new_atom(13i16)); Atom<i16>).value(),
319 13i16
320 );
321 assert_eq!(
322 cast!(KBox::<Any>::from(KBox::new_atom(14i32)); Atom<i32>).value(),
323 14i32
324 );
325 assert_eq!(
326 cast!(KBox::<Any>::from(KBox::new_atom(15i64)); Atom<i64>).value(),
327 15i64
328 );
329 assert_eq!(
330 cast!(KBox::<Any>::from(KBox::new_atom(5.3f32)); Atom<f32>).value(),
331 5.3f32
332 );
333 assert_eq!(cast!(KBox::<Any>::from(KBox::new_atom(true)); Atom<bool>).value(), true);
334 assert_eq!(
335 cast!(KBox::<Any>::from(KBox::new_atom(6.4f64)); Atom<f64>).value(),
336 6.4f64
337 );
338
339 assert_eq!(
340 cast!(KBox::<Any>::from(KBox::new_atom(Second::new(5))); Atom<Second>).value(),
341 Second::new(5)
342 );
343 assert_eq!(
344 cast!(KBox::<Any>::from(KBox::new_atom(Minute::new(6))); Atom<Minute>).value(),
345 Minute::new(6)
346 );
347 assert_eq!(
348 cast!(KBox::<Any>::from(KBox::new_atom(Date::new(2020, 2, 6))); Atom<Date>).value(),
349 Date::new(2020, 2, 6)
350 );
351 assert_eq!(
352 cast!(KBox::<Any>::from(KBox::new_atom(Month::new(8))); Atom<Month>).value(),
353 Month::new(8)
354 );
355 assert_eq!(
356 cast!(KBox::<Any>::from(KBox::new_atom(Time::new(9))); Atom<Time>).value(),
357 Time::new(9)
358 );
359 assert_eq!(
360 cast!(KBox::<Any>::from(KBox::new_atom(DateTime::new(10.0))); Atom<DateTime>).value(),
361 DateTime::new(10.0)
362 );
363 assert_eq!(
364 cast!(
365 KBox::<Any>::from(KBox::new_atom(Timestamp::from_raw(11)));
366 Atom<Timestamp>
367 )
368 .value(),
369 Timestamp::from_raw(11)
370 );
371 assert_eq!(
372 cast!(
373 KBox::<Any>::from(KBox::new_atom(Timespan::from_nanos(12)));
374 Atom<Timespan>
375 )
376 .value(),
377 Timespan::from_nanos(12)
378 );
379
380 assert_eq!(
381 cast!(KBox::<Any>::from(KBox::new_atom(symbol("Foo"))); Atom<Symbol>).value(),
382 symbol("Foo")
383 );
384 #[cfg(feature = "uuid")]
385 assert_eq!(
386 cast!(KBox::<Any>::from(KBox::new_atom(uuid::Uuid::from_bytes([12u8; 16]))); Atom<uuid::Uuid>).value(),
387 uuid::Uuid::from_bytes([12u8; 16])
388 );
389 }
390}