use crate::lang::c::{CType, CompositeType, Documentation, Field, Meta, PrimitiveType, Visibility};
use crate::lang::rust::CTypeInfo;
use crate::patterns::TypePattern;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::ptr::{null, null_mut};
#[repr(C)]
pub struct FFISlice<'a, T> {
data: *const T,
len: u64,
_phantom: PhantomData<&'a T>,
}
impl<'a, T> Default for FFISlice<'a, T> {
fn default() -> Self {
Self {
data: null(),
len: 0,
_phantom: PhantomData,
}
}
}
impl<'a, T> FFISlice<'a, T> {
pub fn from_slice(slice: &'a [T]) -> Self {
FFISlice {
data: slice.as_ptr(),
len: slice.len() as u64,
_phantom: Default::default(),
}
}
pub fn as_slice<'b>(&'b self) -> &'b [T]
where
'a: 'b,
{
if self.data.is_null() {
&[]
} else {
unsafe { std::slice::from_raw_parts(self.data, self.len as usize) }
}
}
}
impl<'a, T> From<&'a [T]> for FFISlice<'a, T> {
fn from(slice: &'a [T]) -> Self {
Self::from_slice(slice)
}
}
impl<'a, T> FFISlice<'a, T>
where
T: 'static,
{
pub fn empty() -> Self {
let x: &'static [T] = &[];
Self::from_slice(x)
}
}
impl<'a, T> Deref for FFISlice<'a, T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
unsafe impl<'a, T> CTypeInfo for FFISlice<'a, T>
where
T: CTypeInfo,
{
#[rustfmt::skip]
fn type_info() -> CType {
let doc_data = Documentation::from_line("Pointer to start of immutable data.");
let doc_len = Documentation::from_line("Number of elements.");
let fields = vec![
Field::with_documentation("data".to_string(), CType::ReadPointer(Box::new(T::type_info())), Visibility::Private, doc_data),
Field::with_documentation("len".to_string(), CType::Primitive(PrimitiveType::U64), Visibility::Private, doc_len),
];
let doc = Documentation::from_line("A pointer to an array of data someone else owns which may not be modified.");
let meta = Meta::with_namespace_documentation(T::type_info().namespace().map(|e| e.into()).unwrap_or_else(String::new), doc, None);
let composite = CompositeType::with_meta(format!("Slice{}", T::type_info().name_within_lib()), fields, meta);
CType::Pattern(TypePattern::Slice(composite))
}
}
#[repr(C)]
pub struct FFISliceMut<'a, T> {
data: *mut T,
len: u64,
_phantom: PhantomData<&'a mut T>,
}
impl<'a, T> Default for FFISliceMut<'a, T> {
fn default() -> Self {
Self {
data: null_mut(),
len: 0,
_phantom: PhantomData,
}
}
}
impl<'a, T> FFISliceMut<'a, T> {
pub fn from_slice(slice: &'a mut [T]) -> Self {
FFISliceMut {
data: slice.as_mut_ptr(),
len: slice.len() as u64,
_phantom: Default::default(),
}
}
pub fn as_slice_mut<'b>(&'b mut self) -> &'b mut [T]
where
'a: 'b,
{
if self.data.is_null() {
&mut []
} else {
unsafe { std::slice::from_raw_parts_mut(self.data, self.len as usize) }
}
}
pub fn as_slice<'b>(&'b self) -> &'b [T]
where
'a: 'b,
{
if self.data.is_null() {
&[]
} else {
unsafe { std::slice::from_raw_parts(self.data, self.len as usize) }
}
}
}
impl<'a, T> FFISliceMut<'a, T>
where
T: 'static,
{
pub fn empty() -> Self {
let x: &'static mut [T] = &mut [];
Self::from_slice(x)
}
}
impl<'a, T> From<&'a mut [T]> for FFISliceMut<'a, T> {
fn from(slice: &'a mut [T]) -> Self {
Self::from_slice(slice)
}
}
impl<'a, T> Deref for FFISliceMut<'a, T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
impl<'a, T> DerefMut for FFISliceMut<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_slice_mut()
}
}
unsafe impl<'a, T> CTypeInfo for FFISliceMut<'a, T>
where
T: CTypeInfo,
{
#[rustfmt::skip]
fn type_info() -> CType {
let doc_data = Documentation::from_line("Pointer to start of mutable data.");
let doc_len = Documentation::from_line("Number of elements.");
let fields = vec![
Field::with_documentation("data".to_string(), CType::ReadPointer(Box::new(T::type_info())), Visibility::Private, doc_data),
Field::with_documentation("len".to_string(), CType::Primitive(PrimitiveType::U64), Visibility::Private, doc_len),
];
let doc = Documentation::from_line("A pointer to an array of data someone else owns which may be modified.");
let meta = Meta::with_namespace_documentation(T::type_info().namespace().map(|e| e.into()).unwrap_or_else(String::new), doc, None);
let composite = CompositeType::with_meta(format!("SliceMut{}", T::type_info().name_within_lib()), fields, meta);
CType::Pattern(TypePattern::SliceMut(composite))
}
}
#[cfg(test)]
mod test {
use crate::patterns::slice::{FFISlice, FFISliceMut};
#[test]
fn can_create_ref() {
let slice = &[0, 1, 2, 3, 5];
let empty = FFISlice::<u8>::empty();
let some = FFISlice::<u8>::from_slice(slice);
assert_eq!(empty.as_slice(), &[]);
assert_eq!(some.as_slice(), slice);
}
#[test]
fn can_create_mut() {
let slice = &mut [0, 1, 2, 3, 5];
let empty = FFISliceMut::<u8>::empty();
let mut some = FFISliceMut::<u8>::from_slice(slice.as_mut());
let sub = &mut some[1..=2];
sub[0] = 6;
some[0] = 5;
assert_eq!(empty.as_slice(), &[]);
assert_eq!(slice, &[5, 6, 2, 3, 5]);
}
}