summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2019-01-23 17:27:06 +0100
committerJustus Winter <justus@sequoia-pgp.org>2019-01-25 14:04:26 +0100
commit71ea3a7f02cc59c5e891c25edbe270e2d9d9d71d (patch)
treef518a31f491e6f6816b4014bbe7bc9768bfdc20d
parentd1e68e97496d0541f3ddd0483f62e185e870c9e4 (diff)
openpgp-ffi: Derive conversion functions.
- This is a framework for dealing with ownership and references at the FFI boundary. Previously, we used macros to do that. This change introduces a more idiomatic interface, we use traits converting from raw pointers of a wrapper type to objects, references, or mutable references to a wrapped type. - For now, we use the wrapped type as wrapper type. We merely introduce a new mechanism replacing the macro-based one. - This patch also converts all the derived functions. - The following patches will convert all the functions that are already using the ffi_wrapper_type. Once this conversion is done, we can introduce our own wrapper type.
-rw-r--r--ffi-macros/src/lib.rs93
-rw-r--r--ffi/src/lib.rs6
-rw-r--r--openpgp-ffi/src/common.rs39
3 files changed, 123 insertions, 15 deletions
diff --git a/ffi-macros/src/lib.rs b/ffi-macros/src/lib.rs
index 4c5df357..fd2bff2c 100644
--- a/ffi-macros/src/lib.rs
+++ b/ffi-macros/src/lib.rs
@@ -1,5 +1,7 @@
//! Common macros for Sequoia's FFI crates.
+#![recursion_limit="256"]
+
use std::collections::HashMap;
extern crate lazy_static;
@@ -172,6 +174,7 @@ pub fn ffi_wrapper_type(args: TokenStream, input: TokenStream) -> TokenStream {
let default_derives: &[DeriveFn] = &[
derive_free,
+ derive_conversion_traits,
];
let mut impls = TokenStream2::new();
for dfn in derive.into_iter().chain(default_derives.iter()) {
@@ -235,6 +238,74 @@ fn derive_functions() -> &'static HashMap<&'static str, DeriveFn>
&MAP
}
+/// Derives prefix_name_conversion_trait.
+fn derive_conversion_traits(_: proc_macro2::Span, _: &str, _: &str,
+ ty: &syn::Type)
+ -> TokenStream2
+{
+ quote! {
+ use MoveFromRaw;
+ impl MoveFromRaw<#ty> for *mut #ty {
+ fn move_from_raw(self) -> #ty {
+ *ffi_param_move!(self)
+ }
+ }
+
+ use RefRaw;
+ impl RefRaw<#ty> for *const #ty {
+ fn ref_raw(self) -> &'static #ty {
+ ffi_param_ref!(self)
+ }
+ }
+
+ use RefMutRaw;
+ impl RefMutRaw<#ty> for *mut #ty {
+ fn ref_mut_raw(self) -> &'static mut #ty {
+ ffi_param_ref_mut!(self)
+ }
+ }
+
+ use MoveIntoRaw;
+ impl MoveIntoRaw<*mut #ty> for #ty {
+ fn move_into_raw(self) -> *mut #ty {
+ Box::into_raw(Box::new(self))
+ }
+ }
+
+ impl MoveIntoRaw<Option<::std::ptr::NonNull<#ty>>>
+ for Option<#ty>
+ {
+ fn move_into_raw(self) -> Option<::std::ptr::NonNull<#ty>> {
+ self.map(|mut v| {
+ let ptr = Box::into_raw(Box::new(v));
+ ::std::ptr::NonNull::new(ptr).unwrap()
+ })
+ }
+ }
+
+ use MoveResultIntoRaw;
+ impl MoveResultIntoRaw<Option<::std::ptr::NonNull<#ty>>>
+ for ::failure::Fallible<#ty>
+ {
+ fn move_into_raw(self, errp: Option<&mut *mut ::failure::Error>)
+ -> Option<::std::ptr::NonNull<#ty>> {
+ match self {
+ Ok(v) => {
+ let ptr = Box::into_raw(Box::new(v));
+ Some(::std::ptr::NonNull::new(ptr).unwrap())
+ },
+ Err(e) => {
+ if let Some(errp) = errp {
+ *errp = box_raw!(e);
+ }
+ None
+ },
+ }
+ }
+ }
+ }
+}
+
/// Derives prefix_name_free.
fn derive_free(span: proc_macro2::Span, prefix: &str, name: &str,
ty: &syn::Type)
@@ -246,10 +317,8 @@ fn derive_free(span: proc_macro2::Span, prefix: &str, name: &str,
/// Frees this object.
#[::ffi_catch_abort] #[no_mangle]
pub extern "system" fn #ident (this: Option<&mut #ty>) {
- if let Some(ptr) = this {
- unsafe {
- drop(Box::from_raw(ptr))
- }
+ if let Some(ref_) = this {
+ drop((ref_ as *mut #wrapper).move_from_raw())
}
}
}
@@ -267,8 +336,7 @@ fn derive_clone(span: proc_macro2::Span, prefix: &str, name: &str,
#[::ffi_catch_abort] #[no_mangle]
pub extern "system" fn #ident (this: *const #ty)
-> *mut #ty {
- let this = ffi_param_ref!(this);
- box_raw!(this.clone())
+ this.ref_raw().clone().move_into_raw()
}
}
}
@@ -286,9 +354,7 @@ fn derive_equal(span: proc_macro2::Span, prefix: &str, name: &str,
pub extern "system" fn #ident (a: *const #ty,
b: *const #ty)
-> bool {
- let a = ffi_param_ref!(a);
- let b = ffi_param_ref!(b);
- a == b
+ a.ref_raw() == b.ref_raw()
}
}
}
@@ -307,8 +373,7 @@ fn derive_to_string(span: proc_macro2::Span, prefix: &str, name: &str,
#[::ffi_catch_abort] #[no_mangle]
pub extern "system" fn #ident (this: *const #ty)
-> *mut ::libc::c_char {
- let this = ffi_param_ref!(this);
- ffi_return_string!(format!("{}", this))
+ ffi_return_string!(format!("{}", this.ref_raw()))
}
}
}
@@ -326,8 +391,7 @@ fn derive_debug(span: proc_macro2::Span, prefix: &str, name: &str,
#[::ffi_catch_abort] #[no_mangle]
pub extern "system" fn #ident (this: *const #ty)
-> *mut ::libc::c_char {
- let this = ffi_param_ref!(this);
- ffi_return_string!(format!("{:?}", this))
+ ffi_return_string!(format!("{:?}", this.ref_raw()))
}
}
}
@@ -346,9 +410,8 @@ fn derive_hash(span: proc_macro2::Span, prefix: &str, name: &str,
-> ::libc::uint64_t {
use ::std::hash::{Hash, Hasher};
- let this = ffi_param_ref!(this);
let mut hasher = ::build_hasher();
- this.hash(&mut hasher);
+ this.ref_raw().hash(&mut hasher);
hasher.finish()
}
}
diff --git a/ffi/src/lib.rs b/ffi/src/lib.rs
index f183f9cc..9b095cd3 100644
--- a/ffi/src/lib.rs
+++ b/ffi/src/lib.rs
@@ -131,6 +131,12 @@ pub mod openpgp {
pub(crate) use openpgp::{
build_hasher,
strndup,
+ MoveFromRaw,
+ RefRaw,
+ RefMutRaw,
+ MoveIntoRaw,
+ MoveResultIntoRaw,
+ Maybe,
};
/* Error handling with implicit context. */
diff --git a/openpgp-ffi/src/common.rs b/openpgp-ffi/src/common.rs
index f764c4b0..f9a2d465 100644
--- a/openpgp-ffi/src/common.rs
+++ b/openpgp-ffi/src/common.rs
@@ -223,6 +223,45 @@ macro_rules! maybe_box_raw {
}
}
+
+/* Support for sequoia_ffi_macros::ffi_wrapper_type-based object
+ * handling. */
+
+/// Moves an object from C to Rust, taking ownership.
+pub(crate) trait MoveFromRaw<T> {
+ /// Moves this object from C to Rust, taking ownership.
+ fn move_from_raw(self) -> T;
+}
+
+/// Moves a reference to an object from C to Rust.
+pub(crate) trait RefRaw<T> {
+ /// Moves this reference to an object from C to Rust.
+ fn ref_raw(self) -> &'static T;
+}
+
+/// Moves a mutable reference to an object from C to Rust.
+pub(crate) trait RefMutRaw<T> {
+ /// Moves this mutable reference to an object from C to Rust.
+ fn ref_mut_raw(self) -> &'static mut T;
+}
+
+/// Moves an object from Rust to C, releasing ownership.
+pub(crate) trait MoveIntoRaw<T> {
+ /// Moves this object from Rust to C, releasing ownership.
+ fn move_into_raw(self) -> T;
+}
+
+/// Moves an object from Rust to C, releasing ownership.
+pub(crate) trait MoveResultIntoRaw<T> {
+ /// Moves this object from Rust to C, releasing ownership.
+ fn move_into_raw(self, errp: Option<&mut *mut ::failure::Error>) -> T;
+}
+
+/// Indicates that a pointer may be NULL.
+pub type Maybe<T> = Option<::std::ptr::NonNull<T>>;
+
+/* Hashing support. */
+
/// Builds hashers for computing hashes.
///
/// This is used to derive Hasher instances for computing hashes of