1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
pub use cffi_impl::marshal;

#[cfg(feature = "url")]
mod url;

mod arc;
mod arc_ref;
mod bool;
mod box_ref;
mod boxed;
mod copy;
mod pathbuf;
mod str;
mod string;
mod unit;
mod vec;
mod vec_ref;

/// Exported functions for consumption via C API
pub mod ffi {
    pub use super::{string::cffi_string_free, vec::cffi_vec_free};
}

#[cfg(feature = "url")]
pub use self::url::UrlMarshaler;

pub use self::bool::BoolMarshaler;
pub use self::pathbuf::PathBufMarshaler;
pub use self::str::StrMarshaler;
pub use self::vec::VecMarshaler;
pub use arc::ArcMarshaler;
pub use arc_ref::ArcRefMarshaler;
pub use box_ref::BoxRefMarshaler;
pub use boxed::BoxMarshaler;
pub use copy::CopyMarshaler;
pub use string::StringMarshaler;
pub use unit::UnitMarshaler;
pub use vec_ref::VecRefMarshaler;

use std::{io, marker::PhantomData};

pub type ErrCallback = Option<extern "C" fn(*const u8, usize)>;
pub type RetCallback<T> = Option<extern "C" fn(T)>;

pub trait ReturnType {
    type Foreign;
    type ForeignTraitObject;

    fn foreign_default() -> Self::Foreign;
    fn foreign_default_trait_object() -> Self::ForeignTraitObject {
        unimplemented!();
    }
}

pub trait InputType {
    // type Local;
    type Foreign;
    type ForeignTraitObject;

    // fn local_default() -> Self::Local;
}

pub trait ToForeign<Local, Foreign>: Sized {
    type Error;
    fn to_foreign(_: Local) -> Result<Foreign, Self::Error>;
}

pub trait ToForeignTraitObject<Local: ?Sized, Foreign: ?Sized> {
    type Error;
    fn to_foreign_trait_object(_: Local) -> Result<crate::TraitObject<Foreign>, Self::Error>;
}

pub trait FromForeign<Foreign, Local>: Sized {
    type Error;
    unsafe fn from_foreign(_: Foreign) -> Result<Local, Self::Error>;
}

#[inline(always)]
pub fn null_ptr_error() -> Box<io::Error> {
    Box::new(io::Error::new(io::ErrorKind::InvalidData, "null pointer"))
}

// Magical catch-all implementation for `Result<Local, Error>`.
// impl<T, Foreign, Local> ToForeign<Result<Local, T::Error>, Foreign> for T
// where
//     T: ToForeign<Local, Foreign>,
// {
//     type Error = T::Error;

//     fn to_foreign(result: Result<Local, T::Error>) -> Result<Foreign, Self::Error> {
//         match result {
//             Ok(v) => <Self as ToForeign<Local, Foreign>>::to_foreign(v),
//             Err(e) => Err(e),
//         }
//     }
// }

#[repr(C)]
pub struct Slice<T: ?Sized> {
    pub data: *mut T,
    pub len: usize,
}

impl<T> Slice<T> {
    unsafe fn cast<U>(self) -> Slice<U> {
        std::mem::transmute::<Slice<T>, Slice<U>>(self)
    }
}

impl<T> std::default::Default for Slice<T> {
    fn default() -> Self {
        Slice {
            data: std::ptr::null_mut(),
            len: 0,
        }
    }
}

impl<T> std::fmt::Debug for Slice<T> {
    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        formatter
            .debug_struct(&format!("Slice<{}>", std::any::type_name::<T>()))
            .field("data", &self.data.cast::<std::ffi::c_void>())
            .field("len", &self.len)
            .finish()
    }
}

impl<T> AsRef<[T]> for Slice<T> {
    fn as_ref(&self) -> &[T] {
        unsafe { std::slice::from_raw_parts(self.data as _, self.len) }
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct TraitObject<T: ?Sized> {
    pub data: *mut (),
    pub vtable: *mut (),
    pub ty: PhantomData<T>,
}

#[macro_export]
macro_rules! trait_object {
    ($input:path : $ty:ty) => {
        std::mem::transmute_copy::<_, $crate::TraitObject<$ty>>(&$input)
    };
}

#[cfg(test)]
mod tests {
    #[test]
    fn test() {}
}