blob: d5dd6e4a8ccdb3d50d1ed6c78ceaec5428b14f45 [file] [log] [blame]
// Part of the Crubit project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
use std::boxed::Box;
use std::panic::catch_unwind;
use std::process;
use std::slice;
/// Returns an `FfiU8SliceBox` containing a copy of the data in `ffi_u8_slice`.
/// The returned `FfiU8SliceBox` must be freed by calling `FreeFfiU8SliceBox()`.
///
/// # Safety
///
/// Expectations:
/// * function expects that param `input` is a FfiU8Slice for a valid array
/// of bytes with the given size.
/// * function expects that param `input` doesn't change during the call, but
/// it is okay if it changes afterwards (because the data from `input` will
/// be copied/boxed into heap).
///
/// Ownership:
/// * function doesn't take ownership of (in other words it borrows) the
/// param `input`
/// * function passes ownership of the returned value to the caller
#[unsafe(no_mangle)]
pub unsafe extern "C" fn AllocFfiU8SliceBox(input: FfiU8Slice) -> FfiU8SliceBox {
FfiU8SliceBox::from_boxed_slice(Box::<[u8]>::from(input.as_slice()))
}
/// Frees `FfiU8SliceBox` allocated by Rust.
///
/// # Safety
///
/// Expectations:
/// * function expects that param `sb` is a valid FfiU8SliceBox that has been
/// allocated earlier by AllocFfiU8SliceBox.
/// * function expects that there are no remaining references to
/// FfiU8SliceBox
///
/// Ownership:
/// * function takes ownership of the param `sb` and frees its memory.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn FreeFfiU8SliceBox(sb: FfiU8SliceBox) {
catch_unwind(|| {
let _ = sb.into_boxed_slice();
})
.unwrap_or_else(|_| process::abort())
}
#[repr(C)]
pub struct FfiU8Slice {
ptr: *const u8,
size: usize,
}
impl FfiU8Slice {
/// Returns an FfiU8Slice pointing to the data of `slice`.
pub fn from_slice(slice: &[u8]) -> FfiU8Slice {
FfiU8Slice { ptr: slice.as_ptr(), size: slice.len() }
}
/// Borrows data pointed to by this `FfiU8Slice` as a slice.
pub fn as_slice(&self) -> &[u8] {
// Safety:
// Instances of `FfiU8Slice` are only created by FFI functions, which are unsafe
// themselves so it's their responsibility to maintain safety.
unsafe { slice::from_raw_parts(self.ptr, self.size) }
}
}
#[repr(C)]
pub struct FfiU8SliceBox {
ptr: *const u8,
size: usize,
}
impl FfiU8SliceBox {
pub fn from_boxed_slice(bytes: Box<[u8]>) -> FfiU8SliceBox {
let slice = Box::leak(bytes);
FfiU8SliceBox { ptr: slice.as_mut_ptr(), size: slice.len() }
}
/// Consumes self and returns boxed slice.
pub fn into_boxed_slice(self) -> Box<[u8]> {
// Safety:
// Instances of `FfiU8SliceBox` are either created by `from_boxed_slice`, which
// is safe, or by FFI functions, which are unsafe themselves so it's
// their responsibility to maintain safety.
unsafe { Box::from_raw(slice::from_raw_parts_mut(self.ptr as *mut u8, self.size)) }
}
}
/// Whether or not the generated binding will have doc comments indicating their
/// source location.
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum SourceLocationDocComment {
Disabled,
Enabled,
}
#[cfg(test)]
mod tests {
use super::*;
use googletest::prelude::*;
#[gtest]
fn test_from_into_ffi_u8_slice_box() {
let slice = Box::<[u8]>::from(*b"Hello World!");
let ffi_slice = FfiU8SliceBox::from_boxed_slice(slice.clone());
assert_eq!(ffi_slice.into_boxed_slice(), slice);
}
}