Skip to content

Commit

Permalink
Add boxed slice, CVec, additional serde implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
h33p committed Dec 24, 2021
1 parent 002bfaa commit fd54980
Show file tree
Hide file tree
Showing 5 changed files with 358 additions and 6 deletions.
57 changes: 57 additions & 0 deletions cglue/src/boxed.rs
@@ -1,4 +1,5 @@
//! # FFI-safe wrapped box.
use crate::slice::CSliceMut;
use crate::trait_group::c_void;
use crate::trait_group::*;
use core::ops::{Deref, DerefMut};
Expand Down Expand Up @@ -57,6 +58,7 @@ impl<T> From<T> for CBox<'_, T> {
}
}

// TODO: Remove? Is this even needed?
impl<T> From<(T, NoContext)> for CBox<'_, T> {
fn from((this, _): (T, NoContext)) -> Self {
let b = Box::new(this);
Expand All @@ -79,3 +81,58 @@ unsafe impl<'a, T> Opaquable for CBox<'a, T> {
unsafe extern "C" fn cglue_drop_box<T>(this: &mut T) {
let _ = Box::from_raw(this);
}

/// FFI-safe (unsized) boxed slice
///
/// This box has a static self reference, alongside a custom drop function.
///
/// The drop function can be called from anywhere, it will free on correct allocator internally.
#[repr(C)]
#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))]
pub struct CSliceBox<'a, T: 'a> {
instance: CSliceMut<'a, T>,
drop_fn: Option<unsafe extern "C" fn(&mut CSliceMut<'a, T>)>,
}

impl<T> Deref for CSliceBox<'_, T> {
type Target = [T];

fn deref(&self) -> &Self::Target {
&self.instance
}
}

impl<T> DerefMut for CSliceBox<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.instance
}
}

impl<T> From<Box<[T]>> for CSliceBox<'_, T> {
fn from(this: Box<[T]>) -> Self {
let instance = Box::leak(this).into();
Self {
instance,
drop_fn: Some(cglue_drop_slice_box::<T>),
}
}
}

impl<T> Drop for CSliceBox<'_, T> {
fn drop(&mut self) {
if let Some(drop_fn) = self.drop_fn.take() {
unsafe { drop_fn(&mut self.instance) };
}
}
}

unsafe impl<'a, T> Opaquable for CSliceBox<'a, T> {
type OpaqueTarget = CSliceBox<'a, c_void>;
}

unsafe extern "C" fn cglue_drop_slice_box<'a, T>(this: &mut CSliceMut<'a, T>) {
// SAFETY: we extend the lifetime of the reference but free the underlying data immediately and
// not use the reference again.
let extended_instance = (this as *mut CSliceMut<_>).as_mut().unwrap();
let _ = Box::from_raw(extended_instance.as_slice_mut());
}
4 changes: 3 additions & 1 deletion cglue/src/lib.rs
Expand Up @@ -942,6 +942,7 @@ pub mod repr_cstring;
pub mod result;
pub mod slice;
pub mod trait_group;
pub mod vec;

pub use ::cglue_macro::{
as_mut, as_ref, cast, cglue_forward, cglue_forward_ext, cglue_impl_group, cglue_trait,
Expand All @@ -966,7 +967,7 @@ pub mod prelude {
pub mod v1 {
pub use crate::{
arc::CArc,
boxed::CBox,
boxed::{CBox, CSliceBox},
callback::{Callback, Callbackable, FeedCallback, FromExtend, OpaqueCallback},
forward::{Forward, ForwardMut, Fwd},
iter::CIterator,
Expand All @@ -975,6 +976,7 @@ pub mod prelude {
result::{CResult, IntError, IntResult},
slice::{CSliceMut, CSliceRef},
trait_group::Opaquable,
vec::CVec,
*,
};

Expand Down
95 changes: 95 additions & 0 deletions cglue/src/option.rs
Expand Up @@ -8,11 +8,18 @@
/// Typical workflow would include temporarily converting into/from COption.
#[repr(C)]
#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))]
#[derive(Clone, Copy)]
pub enum COption<T> {
None,
Some(T),
}

impl<T> Default for COption<T> {
fn default() -> Self {
Self::None
}
}

impl<T> From<Option<T>> for COption<T> {
fn from(opt: Option<T>) -> Self {
match opt {
Expand Down Expand Up @@ -57,3 +64,91 @@ impl<T> COption<T> {
}
}
}

#[cfg(feature = "serde")]
use serde::{de, ser, Deserialize, Serialize};
#[cfg(feature = "serde")]
use core::fmt;
#[cfg(feature = "serde")]
use core::marker::PhantomData;

#[cfg(feature = "serde")]
struct COptionVisitor<T> {
marker: PhantomData<T>,
}

#[cfg(feature = "serde")]
impl<'de, T> de::Visitor<'de> for COptionVisitor<T>
where
T: Deserialize<'de>,
{
type Value = COption<T>;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("option")
}

#[inline]
fn visit_unit<E>(self) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(COption::None)
}

#[inline]
fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(COption::None)
}

#[inline]
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: de::Deserializer<'de>,
{
T::deserialize(deserializer).map(COption::Some)
}

/*#[doc(hidden)]
fn __private_visit_untagged_option<D>(self, deserializer: D) -> Result<Self::Value, ()>
where
D: Deserializer<'de>,
{
Ok(T::deserialize(deserializer).ok())
}*/
}

#[cfg(feature = "serde")]
impl<'de, T> Deserialize<'de> for COption<T>
where
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
deserializer.deserialize_option(COptionVisitor {
marker: PhantomData,
})
}
}

#[cfg(feature = "serde")]
impl<T> Serialize for COption<T>
where
T: Serialize,
{
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
match *self {
COption::Some(ref value) => serializer.serialize_some(value),
COption::None => serializer.serialize_none(),
}
}
}
21 changes: 16 additions & 5 deletions cglue/src/repr_cstring.rs
@@ -1,6 +1,7 @@
//! # Null-terminated transparent C-strings.

use std::prelude::v1::*;
use std::ptr::NonNull;
use std::slice::*;
use std::str::from_utf8_unchecked;

Expand All @@ -15,7 +16,7 @@ pub type c_char = i8;
/// Analog to Rust's `String`, [`ReprCString`] owns the underlying data.
#[repr(transparent)]
#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))]
pub struct ReprCString(*mut c_char);
pub struct ReprCString(NonNull<c_char>);

// The underlying pointer isn't being mutated after construction,
// hence it is safe to assume access to the raw pointer is both Send + Sync
Expand All @@ -37,7 +38,7 @@ unsafe fn string_size(mut ptr: *const c_char) -> usize {
impl From<&[u8]> for ReprCString {
fn from(from: &[u8]) -> Self {
let b = Box::new(from.to_vec().into_boxed_slice());
Self(Box::leak(b).as_mut_ptr() as *mut _)
Self(NonNull::new(Box::leak(b).as_mut_ptr() as *mut _).unwrap())
}
}

Expand All @@ -49,7 +50,7 @@ impl From<&str> for ReprCString {
.chain(Some(0))
.collect::<Vec<_>>()
.into_boxed_slice();
Self(Box::leak(b).as_mut_ptr() as *mut _)
Self(NonNull::new(Box::leak(b).as_mut_ptr() as *mut _).unwrap())
}
}

Expand All @@ -67,7 +68,12 @@ impl<'a> std::borrow::Borrow<ReprCStr<'a>> for ReprCString {

impl AsRef<str> for ReprCString {
fn as_ref(&self) -> &str {
unsafe { from_utf8_unchecked(from_raw_parts(self.0 as *const _, string_size(self.0) - 1)) }
unsafe {
from_utf8_unchecked(from_raw_parts(
self.0.as_ptr() as *const _,
string_size(self.0.as_ptr()) - 1,
))
}
}
}

Expand All @@ -81,7 +87,12 @@ impl std::ops::Deref for ReprCString {

impl Drop for ReprCString {
fn drop(&mut self) {
let _ = unsafe { Box::from_raw(from_raw_parts_mut(self.0 as *mut _, string_size(self.0))) };
let _ = unsafe {
Box::from_raw(from_raw_parts_mut(
self.0.as_ptr() as *mut _,
string_size(self.0.as_ptr()),
))
};
}
}

Expand Down

0 comments on commit fd54980

Please sign in to comment.