From 801929420a3a63285dbba4f9d8ef3c02a8e028ff Mon Sep 17 00:00:00 2001 From: Thibaut Lorrain Date: Tue, 17 Jan 2023 15:42:22 +0100 Subject: [PATCH 1/5] impl CReprOf CDrop and AsRust for arrays --- ffi-convert/src/conversions.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/ffi-convert/src/conversions.rs b/ffi-convert/src/conversions.rs index 9a36b3d..c74a217 100644 --- a/ffi-convert/src/conversions.rs +++ b/ffi-convert/src/conversions.rs @@ -211,7 +211,7 @@ pub trait RawBorrowMut { /// # Safety /// As this is using `*mut T:as_ref()` this is unsafe for exactly the same reasons. unsafe fn raw_borrow_mut<'a>(input: *mut T) - -> Result<&'a mut Self, UnexpectedNullPointerError>; + -> Result<&'a mut Self, UnexpectedNullPointerError>; } /// Trait that allows obtaining a borrowed reference to a type T from a raw pointer to T @@ -360,3 +360,21 @@ impl_rawpointerconverter_for!(u64); impl_rawpointerconverter_for!(f32); impl_rawpointerconverter_for!(f64); impl_rawpointerconverter_for!(bool); + +impl CReprOf<[T; N]> for [T; N] { + fn c_repr_of(input: [T; N]) -> Result<[T; N], CReprOfError> { + Ok(input) + } +} + +impl CDrop for [T; N] { + fn do_drop(&mut self) -> Result<(), CDropError> { + Ok(()) + } +} + +impl AsRust<[T; N]> for [T; N] { + fn as_rust(&self) -> Result<[T; N], AsRustError> { + Ok(self.clone()) + } +} \ No newline at end of file From 6575867a5a94674f361089a5eeeaff2168c4d844 Mon Sep 17 00:00:00 2001 From: Thibaut Lorrain Date: Tue, 17 Jan 2023 16:38:19 +0100 Subject: [PATCH 2/5] better type bounds and bump to edition 2021 --- ffi-convert/Cargo.toml | 2 +- ffi-convert/src/conversions.rs | 44 +++++++++++++++++++++++++++++----- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/ffi-convert/Cargo.toml b/ffi-convert/Cargo.toml index adecee7..9e7fde7 100644 --- a/ffi-convert/Cargo.toml +++ b/ffi-convert/Cargo.toml @@ -2,7 +2,7 @@ name = "ffi-convert" version = "0.6.0-pre" authors = ["Sonos"] -edition = "2018" +edition = "2021" license = "MIT OR Apache-2.0" description = "A collection of utilities to ease conversion between Rust and C-compatible data structures." repository = "https://github.com/sonos/ffi-convert-rs" diff --git a/ffi-convert/src/conversions.rs b/ffi-convert/src/conversions.rs index c74a217..21e0ee8 100644 --- a/ffi-convert/src/conversions.rs +++ b/ffi-convert/src/conversions.rs @@ -361,20 +361,52 @@ impl_rawpointerconverter_for!(f32); impl_rawpointerconverter_for!(f64); impl_rawpointerconverter_for!(bool); -impl CReprOf<[T; N]> for [T; N] { - fn c_repr_of(input: [T; N]) -> Result<[T; N], CReprOfError> { - Ok(input) +impl, const N: usize> CReprOf<[U; N]> for [T; N] where [U; N]: CDrop { + fn c_repr_of(input: [U; N]) -> Result<[T; N], CReprOfError> { + // TODO passing through a Vec here is a bit ugly, but as the conversion call may fail, + // TODO we don't want tobe in the case where we're in the middle of the conversion of the + // TODO array and we encounter an error, hence leaving the array partially uninitialised for + // TODO rust to try to cleanup. the try_map unstable method on array would be nice here + let result_vec: Result, CReprOfError> = input.into_iter().map(T::c_repr_of).collect(); + let vec = result_vec?; + + assert_eq!(vec.len(), N); + + let mut result: [T; N] = unsafe { std::mem::zeroed() }; // we'll replace everything so "should" be good + + for (i, t) in vec.into_iter().enumerate() { + result[i] = t; + } + + Ok(result) } } -impl CDrop for [T; N] { +impl CDrop for [T; N] { fn do_drop(&mut self) -> Result<(), CDropError> { + let result : Result, CDropError> = self.iter_mut().map(T::do_drop).collect(); + result?; Ok(()) } } -impl AsRust<[T; N]> for [T; N] { +impl, T, const N: usize> AsRust<[T; N]> for [U; N] { fn as_rust(&self) -> Result<[T; N], AsRustError> { - Ok(self.clone()) + // TODO passing through a Vec here is a bit ugly, but as the conversion call may fail, + // TODO we don't want tobe in the case where we're in the middle of the conversion of the + // TODO array and we encounter an error, hence leaving the array partially uninitialised for + // TODO rust to try to cleanup. the try_map unstable method on array would be nice here + let result_vec: Result, AsRustError> = self.iter().map(U::as_rust).collect(); + let vec = result_vec?; + + assert_eq!(vec.len(), N); + + let mut result: [T; N] = unsafe { std::mem::zeroed() }; // we'll replace everything so "should" be good + + for (i, t) in vec.into_iter().enumerate() { + result[i] = t; + } + + Ok(result) } } \ No newline at end of file From c70482b4215830fd6d6c0b4d44e1365d859ef4cf Mon Sep 17 00:00:00 2001 From: Thibaut Lorrain Date: Tue, 17 Jan 2023 16:38:30 +0100 Subject: [PATCH 3/5] cargo fmt --- ffi-convert/src/conversions.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/ffi-convert/src/conversions.rs b/ffi-convert/src/conversions.rs index 21e0ee8..49b39ef 100644 --- a/ffi-convert/src/conversions.rs +++ b/ffi-convert/src/conversions.rs @@ -211,7 +211,7 @@ pub trait RawBorrowMut { /// # Safety /// As this is using `*mut T:as_ref()` this is unsafe for exactly the same reasons. unsafe fn raw_borrow_mut<'a>(input: *mut T) - -> Result<&'a mut Self, UnexpectedNullPointerError>; + -> Result<&'a mut Self, UnexpectedNullPointerError>; } /// Trait that allows obtaining a borrowed reference to a type T from a raw pointer to T @@ -361,13 +361,17 @@ impl_rawpointerconverter_for!(f32); impl_rawpointerconverter_for!(f64); impl_rawpointerconverter_for!(bool); -impl, const N: usize> CReprOf<[U; N]> for [T; N] where [U; N]: CDrop { +impl, const N: usize> CReprOf<[U; N]> for [T; N] +where + [U; N]: CDrop, +{ fn c_repr_of(input: [U; N]) -> Result<[T; N], CReprOfError> { // TODO passing through a Vec here is a bit ugly, but as the conversion call may fail, // TODO we don't want tobe in the case where we're in the middle of the conversion of the // TODO array and we encounter an error, hence leaving the array partially uninitialised for // TODO rust to try to cleanup. the try_map unstable method on array would be nice here - let result_vec: Result, CReprOfError> = input.into_iter().map(T::c_repr_of).collect(); + let result_vec: Result, CReprOfError> = + input.into_iter().map(T::c_repr_of).collect(); let vec = result_vec?; assert_eq!(vec.len(), N); @@ -384,7 +388,7 @@ impl, const N: usize> CReprOf<[U; N]> for [T; N] where [U; N]: impl CDrop for [T; N] { fn do_drop(&mut self) -> Result<(), CDropError> { - let result : Result, CDropError> = self.iter_mut().map(T::do_drop).collect(); + let result: Result, CDropError> = self.iter_mut().map(T::do_drop).collect(); result?; Ok(()) } @@ -409,4 +413,4 @@ impl, T, const N: usize> AsRust<[T; N]> for [U; N] { Ok(result) } -} \ No newline at end of file +} From 3e24bea04df6b7f4a7e1b5d49ccce3260956e920 Mon Sep 17 00:00:00 2001 From: Thibaut Lorrain Date: Wed, 18 Jan 2023 15:41:16 +0100 Subject: [PATCH 4/5] support array types in the custom derive --- ffi-convert-derive/src/asrust.rs | 19 +++++++-- ffi-convert-derive/src/cdrop.rs | 11 +++++- ffi-convert-derive/src/creprof.rs | 11 +++++- ffi-convert-derive/src/utils.rs | 65 +++++++++++++++++++++++++------ ffi-convert-tests/src/lib.rs | 34 ++++++++++++++++ ffi-convert/src/conversions.rs | 2 +- 6 files changed, 121 insertions(+), 21 deletions(-) diff --git a/ffi-convert-derive/src/asrust.rs b/ffi-convert-derive/src/asrust.rs index 7e6c7ff..f1891e4 100644 --- a/ffi-convert-derive/src/asrust.rs +++ b/ffi-convert-derive/src/asrust.rs @@ -3,7 +3,7 @@ use proc_macro::TokenStream; use quote::quote; use syn::parse::{Parse, ParseBuffer}; -use crate::utils::{parse_struct_fields, parse_target_type, Field}; +use crate::utils::{parse_struct_fields, parse_target_type, Field, TypeArrayOrTypePath}; pub fn impl_asrust_macro(input: &syn::DeriveInput) -> TokenStream { let struct_name = &input.ident; @@ -34,12 +34,23 @@ pub fn impl_asrust_macro(input: &syn::DeriveInput) -> TokenStream { unsafe { std::ffi::CStr::raw_borrow(self.#field_name) }?.as_rust()? }) } else if field.is_pointer { - quote!( { - let ref_to_struct = unsafe { #field_type::raw_borrow(self.#field_name)? }; + match field_type { + TypeArrayOrTypePath::TypeArray(type_array) => { + quote!( { + let ref_to_array = unsafe { <#type_array>::raw_borrow(self.#field_name)? }; + let converted_array = ref_to_struct.as_rust()?; + converted_array + }) + } + TypeArrayOrTypePath::TypePath(type_path) => { + quote!( { + let ref_to_struct = unsafe { #type_path::raw_borrow(self.#field_name)? }; let converted_struct = ref_to_struct.as_rust()?; converted_struct + }) } - ) + } + } else { quote!(self.#field_name.as_rust()?) }; diff --git a/ffi-convert-derive/src/cdrop.rs b/ffi-convert-derive/src/cdrop.rs index f9da602..b99ddd1 100644 --- a/ffi-convert-derive/src/cdrop.rs +++ b/ffi-convert-derive/src/cdrop.rs @@ -1,4 +1,4 @@ -use crate::utils::{parse_no_drop_impl_flag, parse_struct_fields, Field}; +use crate::utils::{parse_no_drop_impl_flag, parse_struct_fields, Field, TypeArrayOrTypePath}; use proc_macro::TokenStream; use quote::quote; @@ -23,7 +23,14 @@ pub fn impl_cdrop_macro(input: &syn::DeriveInput) -> TokenStream { unsafe { std::ffi::CString::drop_raw_pointer(self.#field_name) }? }) } else if field.is_pointer { - quote!( unsafe { #field_type::drop_raw_pointer(self.#field_name) }? ) + match field_type { + TypeArrayOrTypePath::TypeArray(type_array) => { + quote!( unsafe { <#type_array>::drop_raw_pointer(self.#field_name) }? ) + } + TypeArrayOrTypePath::TypePath(type_path) => { + quote!( unsafe { #type_path::drop_raw_pointer(self.#field_name) }? ) + } + } } else { // the other cases will be handled automatically by rust quote!() diff --git a/ffi-convert-derive/src/creprof.rs b/ffi-convert-derive/src/creprof.rs index 49252f8..74af4c2 100644 --- a/ffi-convert-derive/src/creprof.rs +++ b/ffi-convert-derive/src/creprof.rs @@ -2,7 +2,7 @@ use proc_macro::TokenStream; use quote::quote; -use crate::utils::{parse_struct_fields, parse_target_type, Field}; +use crate::utils::{parse_struct_fields, parse_target_type, Field, TypeArrayOrTypePath}; pub fn impl_creprof_macro(input: &syn::DeriveInput) -> TokenStream { let struct_name = &input.ident; @@ -22,7 +22,14 @@ pub fn impl_creprof_macro(input: &syn::DeriveInput) -> TokenStream { let mut conversion = if field.is_string { quote!(std::ffi::CString::c_repr_of(field)?) } else { - quote!(#field_type::c_repr_of(field)?) + match field_type { + TypeArrayOrTypePath::TypeArray(type_array) => { + quote!(<#type_array>::c_repr_of(field)?) + } + TypeArrayOrTypePath::TypePath(type_path) => { + quote!(#type_path::c_repr_of(field)?) + } + } }; if field.is_pointer { diff --git a/ffi-convert-derive/src/utils.rs b/ffi-convert-derive/src/utils.rs index 4a23925..24b84fe 100644 --- a/ffi-convert-derive/src/utils.rs +++ b/ffi-convert-derive/src/utils.rs @@ -50,10 +50,16 @@ impl<'a> Parse for TargetNameArgs { } } +#[derive(PartialEq, Debug)] +pub enum TypeArrayOrTypePath { + TypeArray(syn::TypeArray), + TypePath(syn::TypePath), +} + pub struct Field<'a> { pub name: &'a syn::Ident, pub target_name: syn::Ident, - pub field_type: syn::TypePath, + pub field_type: TypeArrayOrTypePath, pub type_params: Option, pub is_nullable: bool, pub is_string: bool, @@ -85,6 +91,7 @@ pub fn parse_field(field: &syn::Field) -> Field { let (field_type, type_params) = match inner_field_type { syn::Type::Path(type_path) => generic_path_to_concrete_type_path(type_path), + syn::Type::Array(type_array) => (TypeArrayOrTypePath::TypeArray(type_array), None), _ => panic!("Field type used in this struct is not supported by the proc macro"), }; @@ -145,7 +152,10 @@ pub fn parse_field(field: &syn::Field) -> Field { /// pub fn generic_path_to_concrete_type_path( mut path: syn::TypePath, -) -> (syn::TypePath, Option) { +) -> ( + TypeArrayOrTypePath, + Option, +) { let last_seg: Option<&mut syn::PathSegment> = path.path.segments.last_mut(); if let Some(last_segment) = last_seg { @@ -154,9 +164,12 @@ pub fn generic_path_to_concrete_type_path( { let extracted_type_params = (*bracketed_type_params).clone(); last_segment.arguments = syn::PathArguments::None; - (path, Some(extracted_type_params)) + ( + TypeArrayOrTypePath::TypePath(path), + Some(extracted_type_params), + ) } else { - (path, None) + (TypeArrayOrTypePath::TypePath(path), None) } } else { panic!("Invalid type path: no segments on the TypePath") @@ -179,7 +192,7 @@ mod tests { assert_eq!(extracted_type_param.unwrap().args.len(), 1); assert_eq!( transformed_type_path, - syn::parse_str::("std::mod1::mod2::Foo").unwrap() + TypeArrayOrTypePath::TypePath(syn::parse_str::("std::mod1::mod2::Foo").unwrap()) ); } @@ -192,7 +205,7 @@ mod tests { assert_eq!( transformed_type_path, - syn::parse_str::("std::mod1::mod2::Foo").unwrap() + TypeArrayOrTypePath::TypePath(syn::parse_str::("std::mod1::mod2::Foo").unwrap()) ); assert_eq!(extracted_type_param.unwrap().args.len(), 2) } @@ -207,7 +220,7 @@ mod tests { assert!(extracted_type_params.is_none()); assert_eq!( transformed_path, - syn::parse_str::("std::module1::module2::Hello").unwrap() + TypeArrayOrTypePath::TypePath(syn::parse_str::("std::module1::module2::Hello").unwrap()) ) } @@ -221,7 +234,11 @@ mod tests { assert_eq!(parsed_fields[0].is_pointer, true); assert_eq!(parsed_fields[0].is_nullable, false); - assert_eq!(parsed_fields[0].field_type.path.segments.len(), 2); + if let TypeArrayOrTypePath::TypePath(type_path) = &parsed_fields[0].field_type { + assert_eq!(type_path.path.segments.len(), 2); + } else { + panic!("Unexpected type") + } } #[test] @@ -249,8 +266,20 @@ mod tests { assert_eq!(parsed_fields[0].is_string, false); assert_eq!(parsed_fields[1].is_string, false); - let parsed_path_0 = parsed_fields[0].field_type.path.clone(); - let parsed_path_1 = parsed_fields[1].field_type.path.clone(); + let field_type0 = if let TypeArrayOrTypePath::TypePath(type_path) = &parsed_fields[0].field_type { + type_path + } else { + panic!("unexpected type") + }; + let field_type1 = if let TypeArrayOrTypePath::TypePath(type_path) = &parsed_fields[1].field_type { + type_path + } else { + panic!("unexpected type") + }; + + + let parsed_path_0 = field_type0.path.clone(); + let parsed_path_1 = field_type1.path.clone(); assert_eq!(parsed_path_0.segments.len(), 2); assert_eq!(parsed_path_1.segments.len(), 1); @@ -281,8 +310,20 @@ mod tests { assert_eq!(parsed_fields[0].is_string, false); assert_eq!(parsed_fields[1].is_string, false); - let parsed_path_0 = parsed_fields[0].field_type.path.clone(); - let parsed_path_1 = parsed_fields[1].field_type.path.clone(); + let field_type0 = if let TypeArrayOrTypePath::TypePath(type_path) = &parsed_fields[0].field_type { + type_path + } else { + panic!("unexpected type") + }; + let field_type1 = if let TypeArrayOrTypePath::TypePath(type_path) = &parsed_fields[1].field_type { + type_path + } else { + panic!("unexpected type") + }; + + + let parsed_path_0 = field_type0.path.clone(); + let parsed_path_1 = field_type1.path.clone(); assert_eq!(parsed_path_0.segments.len(), 2); assert_eq!(parsed_path_1.segments.len(), 1); diff --git a/ffi-convert-tests/src/lib.rs b/ffi-convert-tests/src/lib.rs index a6bc82c..8547bdf 100644 --- a/ffi-convert-tests/src/lib.rs +++ b/ffi-convert-tests/src/lib.rs @@ -37,10 +37,12 @@ pub struct Pancake { pub description: Option, pub start: f32, pub end: Option, + pub float_array: [f32; 4], pub dummy: Dummy, pub sauce: Option, pub toppings: Vec, pub layers: Option>, + pub base_layers: [Layer; 3], pub is_delicious: bool, pub range: Range, pub some_futile_info: Option, @@ -61,12 +63,14 @@ pub struct CPancake { start: f32, #[nullable] end: *const f32, + float_array: [f32; 4], dummy: CDummy, #[nullable] sauce: *const CSauce, toppings: *const CArray, #[nullable] layers: *const CArray, + base_layers: [CLayer; 3], is_delicious: bool, pub range: CRange, #[c_repr_of_convert(input.flattened_range.start)] @@ -162,6 +166,7 @@ mod tests { description: Some("I'm delicious ! ".to_string()), start: 0.0, end: Some(2.0), + float_array: [1.0, 2.0, 3.0, 4.0], dummy: Dummy { count: 2, describe: "yo".to_string(), @@ -172,6 +177,20 @@ mod tests { number: 1, subtitle: Some(String::from("first layer")), }]), + base_layers: [ + Layer { + number: 0, + subtitle: Some(String::from("flour")), + }, + Layer { + number: 1, + subtitle: Some(String::from("dough")), + }, + Layer { + number: 2, + subtitle: Some(String::from("tomato")), + }, + ], is_delicious: true, range: Range { start: 20, end: 30 }, some_futile_info: None, @@ -187,6 +206,7 @@ mod tests { description: Some("I'm delicious ! ".to_string()), start: 0.0, end: None, + float_array: [8.0, -1.0, f32::INFINITY, -0.0], dummy: Dummy { count: 2, describe: "yo".to_string(), @@ -194,6 +214,20 @@ mod tests { sauce: None, toppings: vec![], layers: Some(vec![]), + base_layers: [ + Layer { + number: 0, + subtitle: Some(String::from("flour")), + }, + Layer { + number: 1, + subtitle: Some(String::from("dough")), + }, + Layer { + number: 2, + subtitle: Some(String::from("cream")), + }, + ], is_delicious: true, range: Range { start: 50, diff --git a/ffi-convert/src/conversions.rs b/ffi-convert/src/conversions.rs index 49b39ef..1f136d5 100644 --- a/ffi-convert/src/conversions.rs +++ b/ffi-convert/src/conversions.rs @@ -363,7 +363,7 @@ impl_rawpointerconverter_for!(bool); impl, const N: usize> CReprOf<[U; N]> for [T; N] where - [U; N]: CDrop, + [T; N]: CDrop, { fn c_repr_of(input: [U; N]) -> Result<[T; N], CReprOfError> { // TODO passing through a Vec here is a bit ugly, but as the conversion call may fail, From 49825d657edd8a22a79a94abfaed63e6c92de823 Mon Sep 17 00:00:00 2001 From: Thibaut Lorrain Date: Wed, 18 Jan 2023 16:51:05 +0100 Subject: [PATCH 5/5] remove unused apis and clippy fixes --- ffi-convert-derive/src/asrust.rs | 4 +- ffi-convert-derive/src/utils.rs | 84 +++++++++++++------------------- ffi-convert-tests/src/lib.rs | 6 +-- ffi-convert/src/types.rs | 6 +-- 4 files changed, 42 insertions(+), 58 deletions(-) diff --git a/ffi-convert-derive/src/asrust.rs b/ffi-convert-derive/src/asrust.rs index f1891e4..a640ab8 100644 --- a/ffi-convert-derive/src/asrust.rs +++ b/ffi-convert-derive/src/asrust.rs @@ -20,12 +20,12 @@ pub fn impl_asrust_macro(input: &syn::DeriveInput) -> TokenStream { } = field; if field.levels_of_indirection > 1 && !field.is_nullable { - panic!(format!( + panic!( "The CReprOf, AsRust, and CDrop traits cannot be derived automatically: \ The field {} is a pointer field has too many levels of indirection \ ({} in this case). Please implements those traits manually.", field_name, field.levels_of_indirection - )) + ) } let mut conversion = if field.is_string { diff --git a/ffi-convert-derive/src/utils.rs b/ffi-convert-derive/src/utils.rs index 24b84fe..412f5d9 100644 --- a/ffi-convert-derive/src/utils.rs +++ b/ffi-convert-derive/src/utils.rs @@ -1,5 +1,3 @@ -use syn::parse::{Parse, ParseBuffer}; - pub fn parse_target_type(attrs: &[syn::Attribute]) -> syn::Path { let target_type_attribute = attrs .iter() @@ -28,29 +26,7 @@ pub fn parse_struct_fields(data: &syn::Data) -> Vec { } } -struct CReprOfConvertOverrideArgs { - pub convert: syn::Expr, -} - -impl<'a> Parse for CReprOfConvertOverrideArgs { - fn parse(input: &ParseBuffer) -> Result { - let convert = input.parse()?; - Ok(Self { convert }) - } -} - -struct TargetNameArgs { - pub name: syn::Ident, -} - -impl<'a> Parse for TargetNameArgs { - fn parse(input: &ParseBuffer) -> Result { - let name = input.parse()?; - Ok(Self { name }) - } -} - -#[derive(PartialEq, Debug)] +#[derive(PartialEq, Eq, Debug)] pub enum TypeArrayOrTypePath { TypeArray(syn::TypeArray), TypePath(syn::TypePath), @@ -192,7 +168,9 @@ mod tests { assert_eq!(extracted_type_param.unwrap().args.len(), 1); assert_eq!( transformed_type_path, - TypeArrayOrTypePath::TypePath(syn::parse_str::("std::mod1::mod2::Foo").unwrap()) + TypeArrayOrTypePath::TypePath( + syn::parse_str::("std::mod1::mod2::Foo").unwrap() + ) ); } @@ -205,7 +183,9 @@ mod tests { assert_eq!( transformed_type_path, - TypeArrayOrTypePath::TypePath(syn::parse_str::("std::mod1::mod2::Foo").unwrap()) + TypeArrayOrTypePath::TypePath( + syn::parse_str::("std::mod1::mod2::Foo").unwrap() + ) ); assert_eq!(extracted_type_param.unwrap().args.len(), 2) } @@ -220,7 +200,9 @@ mod tests { assert!(extracted_type_params.is_none()); assert_eq!( transformed_path, - TypeArrayOrTypePath::TypePath(syn::parse_str::("std::module1::module2::Hello").unwrap()) + TypeArrayOrTypePath::TypePath( + syn::parse_str::("std::module1::module2::Hello").unwrap() + ) ) } @@ -266,17 +248,18 @@ mod tests { assert_eq!(parsed_fields[0].is_string, false); assert_eq!(parsed_fields[1].is_string, false); - let field_type0 = if let TypeArrayOrTypePath::TypePath(type_path) = &parsed_fields[0].field_type { - type_path - } else { - panic!("unexpected type") - }; - let field_type1 = if let TypeArrayOrTypePath::TypePath(type_path) = &parsed_fields[1].field_type { - type_path - } else { - panic!("unexpected type") - }; - + let field_type0 = + if let TypeArrayOrTypePath::TypePath(type_path) = &parsed_fields[0].field_type { + type_path + } else { + panic!("unexpected type") + }; + let field_type1 = + if let TypeArrayOrTypePath::TypePath(type_path) = &parsed_fields[1].field_type { + type_path + } else { + panic!("unexpected type") + }; let parsed_path_0 = field_type0.path.clone(); let parsed_path_1 = field_type1.path.clone(); @@ -310,17 +293,18 @@ mod tests { assert_eq!(parsed_fields[0].is_string, false); assert_eq!(parsed_fields[1].is_string, false); - let field_type0 = if let TypeArrayOrTypePath::TypePath(type_path) = &parsed_fields[0].field_type { - type_path - } else { - panic!("unexpected type") - }; - let field_type1 = if let TypeArrayOrTypePath::TypePath(type_path) = &parsed_fields[1].field_type { - type_path - } else { - panic!("unexpected type") - }; - + let field_type0 = + if let TypeArrayOrTypePath::TypePath(type_path) = &parsed_fields[0].field_type { + type_path + } else { + panic!("unexpected type") + }; + let field_type1 = + if let TypeArrayOrTypePath::TypePath(type_path) = &parsed_fields[1].field_type { + type_path + } else { + panic!("unexpected type") + }; let parsed_path_0 = field_type0.path.clone(); let parsed_path_1 = field_type1.path.clone(); diff --git a/ffi-convert-tests/src/lib.rs b/ffi-convert-tests/src/lib.rs index 8547bdf..588c674 100644 --- a/ffi-convert-tests/src/lib.rs +++ b/ffi-convert-tests/src/lib.rs @@ -95,7 +95,7 @@ pub struct CSauce { volume: f32, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct Topping { pub amount: i32, } @@ -107,7 +107,7 @@ pub struct CTopping { amount: i32, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct Layer { pub number: i32, pub subtitle: Option, @@ -122,7 +122,7 @@ pub struct CLayer { subtitle: *const libc::c_char, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct Dummy { pub count: i32, pub describe: String, diff --git a/ffi-convert/src/types.rs b/ffi-convert/src/types.rs index d937e13..65171b5 100644 --- a/ffi-convert/src/types.rs +++ b/ffi-convert/src/types.rs @@ -62,7 +62,7 @@ impl CReprOf> for CStringArray { impl CDrop for CStringArray { fn do_drop(&mut self) -> Result<(), CDropError> { - let _ = unsafe { + unsafe { let y = Box::from_raw(std::slice::from_raw_parts_mut( self.data as *mut *mut libc::c_char, self.size, @@ -70,7 +70,7 @@ impl CDrop for CStringArray { for p in y.iter() { let _ = CString::from_raw_pointer(*p)?; // let's not panic if we fail here } - }; + } Ok(()) } } @@ -230,7 +230,7 @@ impl RawPointerConverter> for CArray { /// assert_eq!(foo_converted, foo); /// ``` #[repr(C)] -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct CRange { pub start: T, pub end: T,