Skip to main content

snmalloc_sys/
lib.rs

1#![no_std]
2#![allow(non_camel_case_types)]
3
4use core::ffi::c_void;
5
6extern "C" {
7    /// Allocate the memory with the given alignment and size.
8    /// On success, it returns a pointer pointing to the required memory address.
9    /// On failure, it returns a null pointer.
10    /// The client must assure the following things:
11    /// - `alignment` is greater than zero
12    /// - `alignment` is a power of 2
13    /// The program may be forced to abort if the constrains are not full-filled.
14    pub fn sn_rust_alloc(alignment: usize, size: usize) -> *mut c_void;
15
16    /// De-allocate the memory at the given address with the given alignment and size.
17    /// The client must assure the following things:
18    /// - the memory is acquired using the same allocator and the pointer points to the start position.
19    /// - `alignment` and `size` is the same as allocation
20    /// The program may be forced to abort if the constrains are not full-filled.
21    pub fn sn_rust_dealloc(ptr: *mut c_void, alignment: usize, size: usize) -> c_void;
22
23    /// Behaves like rust_alloc, but also ensures that the contents are set to zero before being returned.
24    pub fn sn_rust_alloc_zeroed(alignment: usize, size: usize) -> *mut c_void;
25
26    /// Re-allocate the memory at the given address with the given alignment and size.
27    /// On success, it returns a pointer pointing to the required memory address.
28    /// The memory content within the `new_size` will remains the same as previous.
29    /// On failure, it returns a null pointer. In this situation, the previous memory is not returned to the allocator.
30    /// The client must assure the following things:
31    /// - the memory is acquired using the same allocator and the pointer points to the start position
32    /// - `alignment` and `old_size` is the same as allocation
33    /// - `alignment` fulfills all the requirements as `rust_alloc`
34    /// The program may be forced to abort if the constrains are not full-filled.
35    pub fn sn_rust_realloc(
36        ptr: *mut c_void,
37        alignment: usize,
38        old_size: usize,
39        new_size: usize,
40    ) -> *mut c_void;
41
42    /// Return the available bytes in a memory block.
43    pub fn sn_rust_usable_size(p: *const c_void) -> usize;
44}
45
46#[cfg(feature = "libc-api")]
47extern "C" {
48    /// Allocate `count` items of `size` length each.
49    /// Returns `null` if `count * size` overflows or on out-of-memory.
50    /// All items are initialized to zero.
51    pub fn sn_calloc(count: usize, size: usize) -> *mut c_void;
52
53    /// Allocate `size` bytes.
54    /// Returns pointer to the allocated memory or null if out of memory.
55    /// Returns a unique pointer if called with `size` 0.
56    pub fn sn_malloc(size: usize) -> *mut c_void;
57
58    /// Re-allocate memory to `newsize` bytes.
59    /// Return pointer to the allocated memory or null if out of memory. If null
60    /// is returned, the pointer `p` is not freed. Otherwise the original
61    /// pointer is either freed or returned as the reallocated result (in case
62    /// it fits in-place with the new size).
63    /// If `p` is null, it behaves as [`sn_malloc`]. If `newsize` is larger than
64    /// the original `size` allocated for `p`, the bytes after `size` are
65    /// uninitialized.
66    pub fn sn_realloc(p: *mut c_void, newsize: usize) -> *mut c_void;
67
68    /// Free previously allocated memory.
69    /// The pointer `p` must have been allocated before (or be null).
70    pub fn sn_free(p: *mut c_void);
71
72    /// Return the available bytes in a memory block.
73    pub fn sn_malloc_usable_size(p: *const c_void) -> usize;
74    
75}
76
77#[cfg(test)]
78mod rust_tests {
79    use super::*;
80
81    #[test]
82    fn it_zero_allocs_correctly() {
83        let ptr = unsafe { sn_rust_alloc_zeroed(8, 1024) } as *mut u8 as *mut [u8; 1024];
84        unsafe {
85            assert!((*ptr).iter().all(|x| *x == 0));
86        };
87        unsafe { sn_rust_dealloc(ptr as *mut c_void, 8, 1024) };
88    }
89
90    #[test]
91    fn it_frees_memory_malloc() {
92        let ptr = unsafe { sn_rust_alloc(8, 8) } as *mut u8;
93        unsafe {
94            *ptr = 127;
95            assert_eq!(*ptr, 127)
96        };
97        unsafe { sn_rust_dealloc(ptr as *mut c_void, 8, 8) };
98    }
99
100    #[test]
101    fn it_reallocs_correctly() {
102        let mut ptr = unsafe { sn_rust_alloc(8, 8) } as *mut u8;
103        unsafe {
104            *ptr = 127;
105            assert_eq!(*ptr, 127)
106        };
107        ptr = unsafe { sn_rust_realloc(ptr as *mut c_void, 8, 8, 16) } as *mut u8;
108        unsafe { assert_eq!(*ptr, 127) };
109        unsafe { sn_rust_dealloc(ptr as *mut c_void, 8, 16) };
110    }
111
112    #[test]
113    fn it_calculates_usable_size() {
114        let ptr = unsafe { sn_rust_alloc(32, 8) } as *mut u8;
115        let usable_size = unsafe { sn_rust_usable_size(ptr as *mut c_void) };
116        assert!(
117            usable_size >= 32,
118            "usable_size should at least equal to the allocated size"
119        );
120        unsafe { sn_rust_dealloc(ptr as *mut c_void, 32, 8) };
121    }
122}
123
124#[cfg(all(test, feature = "libc-api"))]
125mod libc_tests {
126    use super::*;
127
128    #[test]
129    fn it_frees_memory_sn_malloc() {
130        let ptr = unsafe { sn_malloc(8) } as *mut u8;
131        unsafe { sn_free(ptr as *mut c_void) };
132    }
133
134    #[test]
135    fn it_frees_memory_sn_realloc() {
136        let ptr = unsafe { sn_malloc(8) } as *mut u8;
137        let ptr = unsafe { sn_realloc(ptr as *mut c_void, 8) } as *mut u8;
138        unsafe { sn_free(ptr as *mut c_void) };
139    }
140    
141    #[test]
142    fn it_calculates_malloc_usable_size() {
143        let ptr = unsafe { sn_malloc(32) } as *mut u8;
144        let usable_size = unsafe { sn_malloc_usable_size(ptr as *mut c_void) };
145        assert!(
146            usable_size >= 32,
147            "usable_size should at least equal to the allocated size"
148        );
149        unsafe { sn_free(ptr as *mut c_void) };
150    }
151}