kdb/
atom.rs

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/// Atoms are the base primitive values in rust-kdb. You can create a new atom by calling
11/// `KBox::new_atom`, or using the `From`/`Into` traits on a value.
12///
13/// # Examples
14/// ```
15/// use kdb::{KBox, Atom};
16///
17/// let a = KBox::new_atom(42u8); // Creates a KBox<Atom<u8>>
18/// let b: KBox<Atom<u8>> = 27u8.into();
19/// println!("{} dudes!", a.value() + b.value());
20/// ```
21#[repr(transparent)]
22pub struct Atom<T> {
23    k: K,
24    _p: PhantomData<T>,
25}
26
27impl<T: KValue> Atom<T> {
28    /// Returns a copy of the value stored in the atom.
29    #[inline]
30    pub fn value(&self) -> T {
31        unsafe { T::from_k(&self.k) }
32    }
33
34    /// Changes the value stored in th atom.
35    #[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
80// Orphan rules mean I have to implement from type into atom
81// use a macro. Sad.
82macro_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    /// Creates a new atom with the specified value.
122    #[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}