use crate::foreign::*;
impl<T: ?Sized> FreeForeign for Box<T>
where
T: FreeForeign,
{
type Foreign = <T as FreeForeign>::Foreign;
unsafe fn free_foreign(x: *mut Self::Foreign) {
T::free_foreign(x)
}
}
impl<T: ?Sized> CloneToForeign for Box<T>
where
T: CloneToForeign,
{
fn clone_to_foreign(&self) -> OwnedPointer<Self> {
self.as_ref().clone_to_foreign().into()
}
}
impl<T> FromForeign for Box<T>
where
T: FromForeign,
{
unsafe fn cloned_from_foreign(p: *const Self::Foreign) -> Self {
Box::new(T::cloned_from_foreign(p))
}
}
impl<T: ?Sized> BorrowForeign for Box<T>
where
T: BorrowForeign,
{
type Storage<'a>
= <T as BorrowForeign>::Storage<'a>
where
Self: 'a;
fn borrow_foreign(&self) -> BorrowedPointer<Self, Self::Storage<'_>> {
self.as_ref().borrow_foreign().into()
}
}
pub struct BoxStorage<T: ?Sized>(*mut T);
impl<T: ?Sized> Drop for BoxStorage<T> {
fn drop(&mut self) {
unsafe { drop(Box::from_raw(self.0)) }
}
}
impl<T: ?Sized + FreeForeign> FreeForeign for BoxStorage<T> {
type Foreign = <T as FreeForeign>::Foreign;
unsafe fn free_foreign(p: *mut Self::Foreign) {
T::free_foreign(p)
}
}
impl<T: ?Sized + CloneToForeign> CloneToForeign for BoxStorage<T> {
fn clone_to_foreign(&self) -> OwnedPointer<Self> {
let p = unsafe { (*self.0).clone_to_foreign() };
OwnedPointer::from(p)
}
}
impl<T: ?Sized> IntoForeign for Box<T>
where
T: BorrowForeignMut,
{
type Storage = BoxStorage<T>;
fn into_foreign(self) -> BorrowedMutPointer<Self, Self::Storage> {
let raw = Box::into_raw(self);
unsafe {
let p = (*raw).borrow_foreign_mut().as_mut_ptr();
BorrowedMutPointer::new(p, BoxStorage(raw))
}
}
}
impl<T: ?Sized> BorrowForeignMut for Box<T>
where
T: BorrowForeignMut,
{
type Storage<'a>
= <T as BorrowForeignMut>::Storage<'a>
where
Self: 'a;
fn borrow_foreign_mut(&mut self) -> BorrowedMutPointer<Self, Self::Storage<'_>> {
self.as_mut().borrow_foreign_mut().into()
}
}
#[allow(clippy::undocumented_unsafe_blocks)]
#[cfg(test)]
mod tests {
use crate::c_str::c_str;
use crate::foreign::*;
use std::ffi::{c_char, c_void};
#[test]
fn test_box_cloned_from_foreign() {
let s = Box::new("Hello, world!".to_string());
let cstr = c_str!("Hello, world!");
let cloned = unsafe { Box::<String>::cloned_from_foreign(cstr.as_ptr()) };
assert_eq!(s, cloned);
}
#[test]
fn test_box_clone_to_foreign() {
let s = Box::new(128u32);
let cloned = s.clone_to_foreign();
assert_eq!(*s, unsafe { *(cloned.as_ptr()) });
}
#[test]
fn test_box_into_foreign() {
let s = Box::new([128i32, 256i32]);
let consumed = s.into_foreign();
assert_eq!(unsafe { *consumed.as_ptr() }, 128);
assert_eq!(unsafe { *consumed.as_ptr().offset(1) }, 256);
}
#[test]
fn test_box_into_foreign_clone_to_foreign() {
let s = Box::new(128u32);
let consumed = s.into_foreign();
let cloned = consumed.clone_to_foreign();
assert_ne!(cloned.as_ptr(), consumed.as_ptr());
unsafe { assert_eq!(*cloned.as_ptr(), 128) };
}
#[test]
fn test_box_into_foreign_write() {
let b = Box::new(123u16);
let mut consumed = b.into_foreign();
unsafe {
*consumed.as_mut_ptr() = 456;
assert_eq!(*consumed.as_ptr(), 456);
}
let cloned = consumed.clone_to_foreign();
unsafe { assert_eq!(*cloned.as_ptr(), 456) };
}
#[test]
fn test_box_borrow() {
let s = Box::new(c_str!("Hello, world!"));
let borrowed = s.borrow_foreign();
let cloned = unsafe { Box::<String>::cloned_from_foreign(borrowed.as_ptr()) };
assert_eq!(s.to_str().unwrap(), *cloned);
}
#[test]
fn test_box_borrow_clone_to_foreign() {
let b: Box<u16> = Box::new(456);
let p = b.borrow_foreign().clone_to_foreign_ptr();
unsafe {
assert_eq!(*p, 456);
libc::free(p.cast::<c_void>());
}
}
#[test]
fn test_box_borrow_mut() {
let mut s = Box::new(123u16);
let mut borrowed = s.borrow_foreign_mut();
unsafe { *borrowed.as_mut_ptr() = 456 };
assert_eq!(*s, 456);
}
#[test]
fn test_box_unsized() {
let original = c_str!("Hello, world!");
let boxed = original.to_owned().into_bytes_with_nul().into_boxed_slice();
let borrowed = boxed.borrow_foreign();
unsafe {
let len = libc::strlen(borrowed.as_ptr().cast::<c_char>());
assert_eq!(len, original.to_bytes().len());
assert_eq!(
libc::memcmp(
borrowed.as_ptr().cast::<c_void>(),
original.as_ptr().cast::<c_void>(),
len + 1
),
0
);
}
}
}