dotnetrawfilereader_sys/
buffer.rs

1use std::{ops::Deref, ptr, slice};
2
3use netcorehost::{
4    pdcstr,
5    hostfxr::AssemblyDelegateLoader,
6};
7
8/// A sized array for passing heap-allocated memory across the FFI memory boundary to receive
9/// buffers from .NET. Dereferences a `&[T]` otherwise.
10///
11/// # Safety
12/// This type makes heavy use of `unsafe` operations for manual memory management. Take care
13/// when using it as more than an opaque buffer. When it is dropped the memory is freed.
14#[repr(C)]
15pub struct RawVec<T> {
16    pub(crate) data: *mut T,
17    pub(crate) len: usize,
18    pub(crate) capacity: usize,
19}
20
21unsafe impl<T> Send for RawVec<T> {}
22
23unsafe impl<T> Sync for RawVec<T> {}
24
25impl<T> RawVec<T> {
26    /// Releases the owned memory and puts this struct into an unusable, empty
27    /// state. This method is called on `drop`, but it is safe to call repeatedly.
28    pub fn free(&mut self) {
29        if !self.data.is_null() {
30            let owned = unsafe { Box::from_raw(self.data) };
31            drop(owned);
32            self.capacity = 0;
33            self.len = 0;
34            self.data = ptr::null_mut();
35        }
36    }
37
38    pub fn from_vec(buf: Vec<T>) -> Self {
39        let capacity = buf.capacity();
40        let len = buf.len();
41        let data = buf.leak();
42        {
43            RawVec {
44                data: data.as_mut_ptr(),
45                len,
46                capacity,
47            }
48        }
49    }
50}
51
52/// Pretend to by a `&[T]`, a read-only view of the memory
53impl<T> Deref for RawVec<T> {
54    type Target = [T];
55
56    fn deref(&self) -> &Self::Target {
57        unsafe { slice::from_raw_parts_mut(self.data, self.len) }
58    }
59}
60
61impl<T> Drop for RawVec<T> {
62    fn drop(&mut self) {
63        self.free()
64    }
65}
66
67/// A .NET memory allocator that receives a memory address for a [`RawVec`] and
68/// heap-allocates `size` that is "owned" by Rust's memory allocator and gives
69/// it to .NET via the passed pointer.
70pub(crate) extern "system" fn rust_allocate_memory(size: usize, vec: *mut RawVec<u8>) {
71    let buf = vec![0; size];
72    unsafe {
73        *vec = RawVec::from_vec(buf)
74    };
75}
76
77
78/// Configure the `dotnet` runtime to allow it to allocate unmanaged memory from Rust for
79/// specific purposes. Directly depends upon the bundled `dotnet` library.
80pub fn configure_allocator(delegate_loader: &AssemblyDelegateLoader) {
81    let set_rust_allocate_memory = delegate_loader
82        .get_function_with_unmanaged_callers_only::<fn(extern "system" fn(usize, *mut RawVec<u8>))>(
83            pdcstr!("librawfilereader.Exports, librawfilereader"),
84            pdcstr!("SetRustAllocateMemory"),
85        )
86        .unwrap();
87    set_rust_allocate_memory(rust_allocate_memory);
88}