kdb/
any.rs

1use crate::atom::Atom;
2use crate::kapi;
3use crate::kbox::KBox;
4use crate::type_traits::*;
5use crate::{error::ConversionError, Dictionary};
6use crate::{k::K, Table};
7use crate::{k_type::KTypeCode, k_type::MIXED_LIST};
8use crate::{list::List, KError};
9use std::fmt;
10use std::mem;
11
12/// Any represents any KDB value regardless of type.
13/// Unlike atoms or lists you can't do anything with it, except for convert it into an atom or a list.
14/// It is ABI compatible with a K object, so it can be safely used as a parameter or return type for a function.
15/// See the chapter on embedded functions for more information.
16#[repr(transparent)]
17#[derive(PartialEq)]
18pub struct Any {
19    k: K,
20}
21
22impl fmt::Debug for Any {
23    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24        write!(f, "Any(Type={})", self.k.t)
25    }
26}
27
28impl<T: KValue> AsRef<Any> for Atom<T> {
29    fn as_ref(&self) -> &Any {
30        unsafe { &*(self as *const _ as *const _) }
31    }
32}
33
34impl<T: KListable> AsRef<Any> for List<T> {
35    fn as_ref(&self) -> &Any {
36        unsafe { &*(self as *const _ as *const _) }
37    }
38}
39
40impl AsRef<Any> for Dictionary {
41    fn as_ref(&self) -> &Any {
42        unsafe { &*(self as *const _ as *const _) }
43    }
44}
45
46impl AsRef<Any> for Table {
47    fn as_ref(&self) -> &Any {
48        unsafe { &*(self as *const _ as *const _) }
49    }
50}
51
52impl AsRef<Any> for KError {
53    fn as_ref(&self) -> &Any {
54        unsafe { &*(self as *const _ as *const _) }
55    }
56}
57
58impl From<KBox<Dictionary>> for KBox<Any> {
59    fn from(value: KBox<Dictionary>) -> Self {
60        unsafe { mem::transmute(value) }
61    }
62}
63
64impl From<KBox<Table>> for KBox<Any> {
65    fn from(value: KBox<Table>) -> Self {
66        unsafe { mem::transmute(value) }
67    }
68}
69
70impl From<KBox<KError>> for KBox<Any> {
71    fn from(value: KBox<KError>) -> Self {
72        unsafe { mem::transmute(value) }
73    }
74}
75
76impl<T: KListable> From<KBox<List<T>>> for KBox<Any> {
77    fn from(value: KBox<List<T>>) -> Self {
78        unsafe { mem::transmute(value) }
79    }
80}
81
82impl<T: KValue> From<KBox<Atom<T>>> for KBox<Any> {
83    fn from(value: KBox<Atom<T>>) -> Self {
84        unsafe { mem::transmute(value) }
85    }
86}
87
88impl<T: KValue> From<T> for KBox<Any> {
89    fn from(value: T) -> Self {
90        unsafe { mem::transmute(KBox::new_atom(value)) }
91    }
92}
93
94impl KObject for Any {
95    #[inline]
96    fn k_ptr(&self) -> *const K {
97        &self.k
98    }
99
100    #[inline]
101    fn k_ptr_mut(&mut self) -> *mut K {
102        &mut self.k
103    }
104}
105
106impl<T: KListable> AsRef<Any> for KBox<List<T>> {
107    fn as_ref(&self) -> &Any {
108        unsafe { &*(self as *const _ as *const _) }
109    }
110}
111
112impl<T: KValue> AsRef<Any> for KBox<Atom<T>> {
113    fn as_ref(&self) -> &Any {
114        unsafe { &*(self as *const _ as *const _) }
115    }
116}
117
118impl AsRef<Any> for KBox<Dictionary> {
119    fn as_ref(&self) -> &Any {
120        unsafe { &*(self as *const _ as *const _) }
121    }
122}
123
124impl AsRef<Any> for KBox<Table> {
125    fn as_ref(&self) -> &Any {
126        unsafe { &*(self as *const _ as *const _) }
127    }
128}
129
130impl KListable for Any {
131    const LIST_TYPE_CODE: KTypeCode = MIXED_LIST;
132    type ListItem = KBox<Any>;
133
134    unsafe fn join_to(item: Self::ListItem, mut k: *mut K) -> *mut K {
135        // don't r0 this - it's owned by the list now.
136        kapi::jk(&mut k, mem::ManuallyDrop::new(item).k_ptr())
137    }
138}
139
140#[doc(hidden)]
141pub trait KdbCast<T: Sized> {
142    type Output;
143    fn try_cast(self) -> Result<Self::Output, ConversionError>;
144}
145
146impl<T: KObject + KTyped> KdbCast<T> for KBox<Any> {
147    type Output = KBox<T>;
148    fn try_cast(self) -> Result<Self::Output, ConversionError> {
149        unsafe {
150            if (*self.k_ptr()).t != T::K_TYPE {
151                Err(ConversionError::InvalidKCast {
152                    from: (*self.k_ptr()).t,
153                    to: T::K_TYPE,
154                })
155            } else {
156                #[allow(clippy::clippy::transmute_ptr_to_ptr)]
157                Ok(mem::transmute(self))
158            }
159        }
160    }
161}
162
163impl<'a, T: 'a + KObject + KTyped> KdbCast<T> for &'a KBox<Any> {
164    type Output = &'a KBox<T>;
165    fn try_cast(self) -> Result<Self::Output, ConversionError> {
166        unsafe {
167            if (*self.k_ptr()).t != T::K_TYPE {
168                Err(ConversionError::InvalidKCast {
169                    from: (*self.k_ptr()).t,
170                    to: T::K_TYPE,
171                })
172            } else {
173                #[allow(clippy::clippy::transmute_ptr_to_ptr)]
174                Ok(mem::transmute(self))
175            }
176        }
177    }
178}
179
180impl<'a, T: 'a + KObject + KTyped> KdbCast<T> for &'a Any {
181    type Output = &'a T;
182    fn try_cast(self) -> Result<Self::Output, ConversionError> {
183        unsafe {
184            if (*self.k_ptr()).t != T::K_TYPE {
185                Err(ConversionError::InvalidKCast {
186                    from: (*self.k_ptr()).t,
187                    to: T::K_TYPE,
188                })
189            } else {
190                #[allow(clippy::clippy::transmute_ptr_to_ptr)]
191                Ok(mem::transmute(self))
192            }
193        }
194    }
195}
196
197/// Tries to cast a KBox<Any>, &KBox<Any> or &Any to another KDB type.
198///
199/// returns a result containing the KDB type, or a `ConversionError`.
200///
201/// # Example
202///
203/// ```
204/// # use kdb::{try_cast, symbol, Any, Atom, KBox, Symbol};
205/// let a: KBox<Any> = symbol("Hello").into();
206/// assert_eq!(symbol("Hello"), try_cast!(a; Atom<Symbol>).unwrap().value());
207/// ```
208#[macro_export]
209macro_rules! try_cast {
210    ($ex:expr; $t:ty) => {
211        $crate::KdbCast::<$t>::try_cast($ex)
212    };
213}
214
215/// Cast a KBox<Any>, &KBox<Any> or &Any to another KDB type.
216///
217/// If the KDB type is anything other than the expected one, the cast will panic.
218///
219/// # Example
220///
221/// ```
222/// # use kdb::{cast, symbol, Any, Atom, KBox, Symbol};
223/// let a: KBox<Any> = symbol("Hello").into();
224/// assert_eq!(symbol("Hello"), cast!(a; Atom<Symbol>).value());
225/// ```
226#[macro_export]
227macro_rules! cast {
228    ($ex:expr; $t:ty) => {
229        $crate::KdbCast::<$t>::try_cast($ex).unwrap()
230    };
231}