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}