rusty_cffi/
containers.rs

1//! Container to make working with arrays easier.
2//!
3//! This module defines a type [DataContainer], which
4//! is a simple C data structure that can be flexibly converted to
5//! various Rust types.
6
7use crate::{assert_dtype, get_itemsize, ConversionType, DTYPE, MUTABILITY, OWNERSHIP};
8use libc::{c_void, size_t};
9
10/// A data container for communication with a C ABI.
11///
12/// The basic task of this container is to provide a C ABI
13/// compatible type to store arbitrary data arrays, and
14/// to convert them back and forth into corresponding Rust types.
15pub struct RustyDataContainer {
16    /// The number of elements in the Array.
17    nitems: size_t,
18    /// The size in bytes of each element.
19    itemsize: size_t,
20    /// The capacity of the underlying array.
21    /// This is only needed if the container is allocated
22    /// from a Rust Vec.
23    capacity: size_t,
24    /// The type of the data.
25    dtype: DTYPE,
26    /// The ownership of the data. It is either
27    /// [OWNERSHIP::Owner] or [OWNERSHIP::NotOwner].
28    /// The underlying data can only be destroyed if
29    /// [DataContainer] is owner.
30    is_owner: OWNERSHIP,
31    /// Mutability of the underlying data. It is either
32    /// [MUTABILITY::Mutable] or [MUTABILITY::NotMutable].
33    is_mutable: MUTABILITY,
34    /// A pointer to the underlying data.
35    data: *mut c_void,
36}
37
38impl RustyDataContainer {
39    /// Create a new non-owning and non-mutable container from a given slice.
40    pub fn from_slice<T: ConversionType>(slice: &[T]) -> Self {
41        Self {
42            nitems: slice.len(),
43            capacity: slice.len(),
44            itemsize: crate::get_size::<T>(),
45            dtype: crate::get_dtype::<T>(),
46            is_owner: OWNERSHIP::NotOwner,
47            is_mutable: MUTABILITY::NotMutable,
48            data: slice.as_ptr() as *mut c_void,
49        }
50    }
51    /// Create a new non-owning but mutable container from a given slice.
52    pub fn from_slice_mut<T: ConversionType>(slice: &mut [T]) -> Self {
53        Self {
54            nitems: slice.len(),
55            capacity: slice.len(),
56            itemsize: crate::get_size::<T>(),
57            dtype: crate::get_dtype::<T>(),
58            is_owner: OWNERSHIP::NotOwner,
59            is_mutable: MUTABILITY::Mutable,
60            data: slice.as_ptr() as *mut c_void,
61        }
62    }
63
64    // To boxed pointer.
65    pub fn to_box(self) -> Box<RustyDataContainer> {
66        Box::new(self)
67    }
68
69    pub unsafe fn to_vec<T: ConversionType>(mut self) -> Vec<T> {
70        assert_eq!(self.is_owner, OWNERSHIP::Owner);
71        assert_dtype::<T>(self.dtype);
72        // Have to remove ownership as the Vec takes ownership of the
73        // contained data.
74        self.is_owner = OWNERSHIP::NotOwner;
75        Vec::<T>::from_raw_parts(self.data as *mut T, self.nitems, self.capacity)
76    }
77
78    /// Get a mutable reference to a RustyDataContainer from a ptr.
79    /// Ensures that the destructor of the data container is not run.
80    pub fn leak_mut(ptr: Option<Box<RustyDataContainer>>) -> &'static mut RustyDataContainer {
81        let ptr_ref = Box::leak(ptr.unwrap());
82        assert_eq!(ptr_ref.is_mutable, MUTABILITY::Mutable);
83        ptr_ref
84    }
85
86    /// Get a reference to a RustyDataContainer from a ptr.
87    /// Ensures that the destructor of the data container is not run.
88    pub fn leak(ptr: Option<Box<RustyDataContainer>>) -> &'static RustyDataContainer {
89        Box::leak(ptr.unwrap())
90    }
91
92    /// Create a new owning and mutable container from a vector.
93    /// The vector is consumed by this method.
94    pub fn from_vec<T: ConversionType>(vec: Vec<T>) -> Self {
95        let nitems = vec.len();
96        let capacity = vec.capacity();
97        let data = vec.as_ptr() as *mut c_void;
98        std::mem::forget(vec);
99        Self {
100            nitems,
101            capacity,
102            itemsize: crate::get_size::<T>(),
103            dtype: crate::get_dtype::<T>(),
104            is_owner: OWNERSHIP::Owner,
105            is_mutable: MUTABILITY::Mutable,
106            data,
107        }
108    }
109
110    /// Get a representation of the data as slice.
111    /// This method does not take ownership of the container associated with `ptr`.
112    pub unsafe fn as_slice<T: ConversionType>(
113        ptr: Option<Box<RustyDataContainer>>,
114    ) -> &'static [T] {
115        let container = RustyDataContainer::leak(ptr);
116        assert_dtype::<T>(container.dtype);
117        std::slice::from_raw_parts::<'static, T>(container.data as *const T, container.nitems)
118    }
119
120    /// Get a representation of the data as mutable slice.
121    /// This method does not take ownership of the container associated with `ptr`.
122    pub unsafe fn as_slice_mut<T: ConversionType>(
123        ptr: Option<Box<RustyDataContainer>>,
124    ) -> &'static mut [T] {
125        let container = RustyDataContainer::leak_mut(ptr);
126        assert_eq!(container.is_mutable, MUTABILITY::Mutable);
127        std::slice::from_raw_parts_mut::<'static, T>(container.data as *mut T, container.nitems)
128    }
129}
130
131impl Drop for RustyDataContainer {
132    /// Destroy a data container. If the container owns the
133    /// data the corresponding memory is also deallocated.
134    fn drop(&mut self) {
135        if let OWNERSHIP::Owner = self.is_owner {
136            let len = self.nitems * self.itemsize;
137            let cap = self.capacity * self.itemsize;
138            let vec = unsafe { Vec::<u8>::from_raw_parts(self.data as *mut u8, len, cap) };
139            drop(vec);
140        }
141    }
142}
143
144/// Destroy a data container.
145#[no_mangle]
146pub extern "C" fn rusty_data_container_destroy(_: Option<Box<RustyDataContainer>>) {}
147
148/// Create a new f32 data container.
149#[no_mangle]
150pub extern "C" fn rusty_data_container_new_f32(nitems: size_t) -> Box<RustyDataContainer> {
151    RustyDataContainer::from_vec(vec![0 as f32; nitems]).to_box()
152}
153
154/// Create a new f64 data container.
155#[no_mangle]
156pub extern "C" fn rusty_data_container_new_f64(nitems: size_t) -> Box<RustyDataContainer> {
157    RustyDataContainer::from_vec(vec![0 as f64; nitems]).to_box()
158}
159
160/// Create a new u8 data container.
161#[no_mangle]
162pub extern "C" fn rusty_data_container_new_u8(nitems: size_t) -> Box<RustyDataContainer> {
163    RustyDataContainer::from_vec(vec![0 as u8; nitems]).to_box()
164}
165
166/// Create a new u32 data container.
167#[no_mangle]
168pub extern "C" fn rusty_data_container_new_u32(nitems: size_t) -> Box<RustyDataContainer> {
169    RustyDataContainer::from_vec(vec![0 as u32; nitems]).to_box()
170}
171
172/// Create a new u64 data container.
173#[no_mangle]
174pub extern "C" fn rusty_data_container_new_u64(nitems: size_t) -> Box<RustyDataContainer> {
175    RustyDataContainer::from_vec(vec![0 as u64; nitems]).to_box()
176}
177
178/// Create a new i8 data container.
179#[no_mangle]
180pub extern "C" fn rusty_data_container_new_i8(nitems: size_t) -> Box<RustyDataContainer> {
181    RustyDataContainer::from_vec(vec![0 as i8; nitems]).to_box()
182}
183
184/// Create a new i32 data container.
185#[no_mangle]
186pub extern "C" fn rusty_data_container_new_i32(nitems: size_t) -> Box<RustyDataContainer> {
187    RustyDataContainer::from_vec(vec![0 as i32; nitems]).to_box()
188}
189
190/// Create a new i64 data container.
191#[no_mangle]
192pub extern "C" fn rusty_data_container_new_i64(nitems: size_t) -> Box<RustyDataContainer> {
193    RustyDataContainer::from_vec(vec![0 as i64; nitems]).to_box()
194}
195
196/// Create a new usize data container.
197#[no_mangle]
198pub extern "C" fn rusty_data_container_new_usize(nitems: size_t) -> Box<RustyDataContainer> {
199    RustyDataContainer::from_vec(vec![0 as usize; nitems]).to_box()
200}
201
202
203/// Get nitems
204#[no_mangle]
205pub extern "C" fn rusty_data_container_get_nitems(ptr: Option<Box<RustyDataContainer>>) -> size_t {
206    RustyDataContainer::leak(ptr).nitems
207}
208
209/// Get itemsize
210#[no_mangle]
211pub extern "C" fn rusty_data_container_get_itemsize(
212    ptr: Option<Box<RustyDataContainer>>,
213) -> size_t {
214    RustyDataContainer::leak(ptr).itemsize
215}
216
217/// Get dtype
218#[no_mangle]
219pub extern "C" fn rusty_data_container_get_dtype(ptr: Option<Box<RustyDataContainer>>) -> DTYPE {
220    RustyDataContainer::leak(ptr).dtype
221}
222
223/// Get is_owner
224#[no_mangle]
225pub extern "C" fn rusty_data_container_get_is_owner(
226    ptr: Option<Box<RustyDataContainer>>,
227) -> OWNERSHIP {
228    RustyDataContainer::leak(ptr).is_owner
229}
230
231/// Get is_mutable
232#[no_mangle]
233pub extern "C" fn rusty_data_container_get_is_mutable(
234    ptr: Option<Box<RustyDataContainer>>,
235) -> MUTABILITY {
236    RustyDataContainer::leak(ptr).is_mutable
237}
238
239/// Get data
240#[no_mangle]
241pub extern "C" fn rusty_data_container_get_data(
242    ptr: Option<Box<RustyDataContainer>>,
243) -> *mut c_void {
244    RustyDataContainer::leak(ptr).data
245}
246
247#[no_mangle]
248pub extern "C" fn new_from_pointer(
249    ptr: *mut c_void,
250    nitems: size_t,
251    dtype: DTYPE,
252    is_mutable: MUTABILITY,
253) -> Box<RustyDataContainer> {
254    RustyDataContainer {
255        nitems,
256        capacity: nitems,
257        itemsize: get_itemsize(dtype) as size_t,
258        dtype,
259        is_owner: OWNERSHIP::NotOwner,
260        is_mutable,
261        data: ptr,
262    }
263    .to_box()
264}
265