kdb/
kbox.rs

1use crate::type_traits::KObject;
2use crate::{k::K, kapi};
3use std::mem::ManuallyDrop;
4use std::ops::Deref;
5use std::ptr::NonNull;
6use std::{fmt, ops::DerefMut};
7
8/// Represents a memory managed K pointer. They are the
9/// KDB equivalent of a Rust Box, a zero overhead wrapper
10/// around a K pointer. It will call `r0` to decrement the reference
11/// count when it is dropped.
12#[repr(transparent)]
13#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub struct KBox<T: KObject> {
15    pub(crate) k: NonNull<T>,
16}
17
18impl<T: KObject> KBox<T> {
19    /// Converts a box into a raw unmanged K pointer.
20    /// Note that into raw will consume the KBox, and not call
21    /// r0, so it's possible to leak memory by doing this.
22    pub fn into_raw(self) -> *mut T {
23        ManuallyDrop::new(self).k.as_ptr()
24    }
25
26    /// Converts a raw K pointer into a boxed K object.
27    /// This is the reciprocal of into_raw
28    ///
29    /// # Safety
30    ///
31    /// The type of the k pointer must match the type of the KBox being used.
32    /// The pointer must not be null.
33    ///
34    /// Do not use this to take ownership of a kdb callback function parameter,
35    /// use from_shared instead.
36    pub unsafe fn from_raw(k: *mut K) -> Self {
37        KBox {
38            k: NonNull::new_unchecked(k as *mut T),
39        }
40    }
41
42    /// Takes a reference and calls r1, incrementing the reference count
43    /// and "re-boxing" it. Typically this is a bad thing as you have multiple
44    /// owned references and kdb does not provide equivalent guarantees to rust
45    /// about what happens to shared references (especially when reallocating a list for example)
46    ///
47    /// However in the embedded case, where you do not own the parameter and you wish to manipulate it
48    /// without copying the data, then you need this functionality.
49    ///
50    /// # Safety
51    ///
52    /// A reference should not be owned by more than one `KBox` instance.
53    pub unsafe fn from_shared(t: &mut T) -> Self {
54        KBox {
55            k: NonNull::new_unchecked(kapi::r1(t.k_ptr_mut()) as *mut T),
56        }
57    }
58}
59
60impl<T: KObject> Drop for KBox<T> {
61    fn drop(&mut self) {
62        unsafe {
63            kapi::r0(self.k.as_mut().k_ptr_mut());
64        }
65    }
66}
67
68impl<T: KObject> Deref for KBox<T> {
69    type Target = T;
70
71    fn deref(&self) -> &T {
72        unsafe { self.k.as_ref() }
73    }
74}
75
76impl<T: KObject> DerefMut for KBox<T> {
77    fn deref_mut(&mut self) -> &mut T {
78        unsafe { self.k.as_mut() }
79    }
80}
81
82impl<T: KObject> AsRef<T> for KBox<T> {
83    fn as_ref(&self) -> &T {
84        unsafe { self.k.as_ref() }
85    }
86}
87
88impl<T: KObject + fmt::Debug> fmt::Debug for KBox<T> {
89    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90        write!(f, "KBox({:?})", self.as_ref())
91    }
92}
93
94impl<T: KObject + fmt::Display> fmt::Display for KBox<T> {
95    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96        write!(f, "{}", self.as_ref())
97    }
98}