unsafe_libopus/
externs.rs

1//! Contains implementation for some common libc functions.
2//!
3//! This is used to avoid unnecessarily linking to libc.
4
5use core::mem::{self, MaybeUninit};
6use core::ptr;
7use core::slice;
8use std::alloc::{self as rust, Layout};
9
10const HEADER: usize = mem::size_of::<usize>();
11
12const MALLOC_ALIGN: usize = mem::align_of::<usize>();
13
14/// Implement `malloc` in terms of rust's `alloc`.
15///
16/// It stores the size of the allocation in the first 8 bytes of the allocation.
17pub unsafe fn malloc(size: u64) -> *mut core::ffi::c_void {
18    let size = HEADER + size as usize;
19    let layout = Layout::from_size_align_unchecked(size, MALLOC_ALIGN);
20    let memory = rust::alloc(layout);
21    if memory.is_null() {
22        rust::handle_alloc_error(layout);
23    }
24    memory.cast::<usize>().write(size);
25    let result = memory.add(HEADER).cast();
26    result
27}
28
29/// Malloc, but zero out the memory.
30pub unsafe fn calloc(n: u64, size: u64) -> *mut core::ffi::c_void {
31    let mem = malloc(n * size);
32    ptr::write_bytes(mem, 0, (n * size) as usize);
33    mem
34}
35
36pub unsafe fn realloc(ptr: *mut core::ffi::c_void, new_size: u64) -> *mut core::ffi::c_void {
37    if ptr.is_null() {
38        return calloc(1, new_size);
39    }
40
41    let mut memory = ptr.cast::<u8>().sub(HEADER);
42    let size = memory.cast::<usize>().read();
43    let layout = Layout::from_size_align_unchecked(size, MALLOC_ALIGN);
44    let new_size = HEADER + new_size as usize;
45    memory = rust::realloc(memory, layout, new_size);
46    if memory.is_null() {
47        let layout = Layout::from_size_align_unchecked(new_size, MALLOC_ALIGN);
48        rust::handle_alloc_error(layout);
49    }
50    memory.cast::<usize>().write(new_size);
51    memory.add(HEADER).cast()
52}
53
54pub unsafe fn free(ptr: *mut core::ffi::c_void) {
55    if ptr == ptr::null_mut() {
56        return;
57    }
58
59    let memory = ptr.cast::<u8>().sub(HEADER);
60    let size = memory.cast::<usize>().read();
61    let layout = Layout::from_size_align_unchecked(size, MALLOC_ALIGN);
62    rust::dealloc(memory, layout);
63}
64
65pub unsafe fn memcmp(
66    lhs: *const core::ffi::c_void,
67    rhs: *const core::ffi::c_void,
68    count: u64,
69) -> i32 {
70    let lhs = slice::from_raw_parts(lhs.cast::<u8>(), count as usize);
71    let rhs = slice::from_raw_parts(rhs.cast::<u8>(), count as usize);
72    lhs.cmp(rhs) as i32
73}
74
75pub unsafe fn memcpy(
76    dest: *mut core::ffi::c_void,
77    src: *const core::ffi::c_void,
78    count: u64,
79) -> *mut core::ffi::c_void {
80    ptr::copy_nonoverlapping(
81        src.cast::<MaybeUninit<u8>>(),
82        dest.cast::<MaybeUninit<u8>>(),
83        count as usize,
84    );
85    dest
86}
87
88pub unsafe fn memmove(
89    dest: *mut core::ffi::c_void,
90    src: *const core::ffi::c_void,
91    count: u64,
92) -> *mut core::ffi::c_void {
93    ptr::copy(
94        src.cast::<MaybeUninit<u8>>(),
95        dest.cast::<MaybeUninit<u8>>(),
96        count as usize,
97    );
98    dest
99}
100
101pub unsafe fn memset(dest: *mut core::ffi::c_void, ch: i32, count: u64) -> *mut core::ffi::c_void {
102    ptr::write_bytes(dest.cast::<u8>(), ch as u8, count as usize);
103    dest
104}