diff --git a/iceoryx2-ffi/ffi/README.md b/iceoryx2-ffi/ffi/README.md index 7d72cab2..5012b78d 100644 --- a/iceoryx2-ffi/ffi/README.md +++ b/iceoryx2-ffi/ffi/README.md @@ -13,7 +13,7 @@ The type erasure is usually done in two stages with `iox2_foo_storage_t` and `iox2_foo_t`. The `iox2_foo_storage_t` is the storage for the Rust type `Option` and must match the size and alignment of `Option`. -If the internal storage must hold multiple types, the size and alignment is respectively the max value of the types. +If the internal storage must hold multiple types, a union can be used. The struct is not supposed to be used standalone but always in combination with an `iox2_foo_t`. Assuming the size is 160 and the alignment is 8, then the storage is defined as following ```rs diff --git a/iceoryx2-ffi/ffi/src/node.rs b/iceoryx2-ffi/ffi/src/node.rs index a81e104f..2d7e654f 100644 --- a/iceoryx2-ffi/ffi/src/node.rs +++ b/iceoryx2-ffi/ffi/src/node.rs @@ -19,12 +19,10 @@ use crate::{ use iceoryx2::node::{NodeListFailure, NodeView}; use iceoryx2::prelude::*; -use iceoryx2::service; -use iceoryx2_bb_elementary::math::max; use iceoryx2_bb_elementary::static_assert::*; use core::ffi::{c_int, c_void}; -use core::mem::{align_of, size_of, MaybeUninit}; +use core::mem::{align_of, size_of, ManuallyDrop, MaybeUninit}; use std::alloc::{alloc, dealloc, Layout}; // BEGIN type definition @@ -49,46 +47,60 @@ impl IntoCInt for NodeListFailure { } } +pub(crate) union NodeUnion { + ipc: ManuallyDrop>, + local: ManuallyDrop>, +} + +impl NodeUnion { + pub(crate) fn new_ipc(node: Node) -> Self { + Self { + ipc: ManuallyDrop::new(node), + } + } + pub(crate) fn new_local(node: Node) -> Self { + Self { + local: ManuallyDrop::new(node), + } + } +} + #[repr(C)] -#[repr(align(8))] // magic number; the larger one of align_of::>() and align_of::>() +#[repr(align(8))] // alignment of Option pub struct iox2_node_storage_t { - internal: [u8; 8], // magic number; the larger one of size_of::>() and size_of::>() + internal: [u8; 16], // magic number obtained with size_of::>() } impl iox2_node_storage_t { const fn assert_storage_layout() { - const MAX_NODE_ALIGNMENT: usize = max( - align_of::>>(), - align_of::>>(), + static_assert_ge::< + { align_of::() }, + { align_of::>() }, + >(); + static_assert_ge::<{ size_of::() }, { size_of::>() }>( ); - const MAX_NODE_SIZE: usize = max( - size_of::>>(), - size_of::>>(), - ); - static_assert_ge::<{ align_of::() }, { MAX_NODE_ALIGNMENT }>(); - static_assert_ge::<{ size_of::() }, { MAX_NODE_SIZE }>(); } - fn init(&mut self, node: Node) { + fn init(&mut self, node: NodeUnion) { iox2_node_storage_t::assert_storage_layout(); - unsafe { &mut *(self as *mut Self).cast::>>>() } + unsafe { &mut *(self as *mut Self).cast::>>() } .write(Some(node)); } - unsafe fn as_option_mut(&mut self) -> &mut Option> { - &mut *(self as *mut Self).cast::>>() + unsafe fn as_option_mut(&mut self) -> &mut Option { + &mut *(self as *mut Self).cast::>() } - unsafe fn as_option_ref(&self) -> &Option> { - &*(self as *const Self).cast::>>() + unsafe fn as_option_ref(&self) -> &Option { + &*(self as *const Self).cast::>() } - unsafe fn _as_mut(&mut self) -> &mut Node { + unsafe fn as_mut(&mut self) -> &mut NodeUnion { self.as_option_mut().as_mut().unwrap() } - unsafe fn as_ref(&self) -> &Node { + unsafe fn as_ref(&self) -> &NodeUnion { self.as_option_ref().as_ref().unwrap() } } @@ -103,10 +115,10 @@ pub struct iox2_node_t { } impl iox2_node_t { - pub(crate) fn init( + pub(crate) fn init( &mut self, service_type: iox2_service_type_e, - node: Node, + node: NodeUnion, deleter: fn(*mut iox2_node_t), ) { self.service_type = service_type; @@ -183,11 +195,9 @@ pub unsafe extern "C" fn iox2_node_name(node_handle: iox2_node_h) -> iox2_node_n let node_struct = &mut *iox2_node_t::cast(node_handle); match node_struct.service_type { - iox2_service_type_e::IPC => { - node_struct.node.as_ref::().name() as *const _ as *const _ - } + iox2_service_type_e::IPC => node_struct.node.as_ref().ipc.name() as *const _ as *const _, iox2_service_type_e::LOCAL => { - node_struct.node.as_ref::().name() as *const _ as *const _ + node_struct.node.as_ref().local.name() as *const _ as *const _ } } } @@ -204,11 +214,9 @@ pub unsafe extern "C" fn iox2_node_config(node_handle: iox2_node_h) -> iox2_conf let node_struct = &mut *iox2_node_t::cast(node_handle); match node_struct.service_type { - iox2_service_type_e::IPC => { - node_struct.node.as_ref::().config() as *const _ as *const _ - } + iox2_service_type_e::IPC => node_struct.node.as_ref().ipc.config() as *const _ as *const _, iox2_service_type_e::LOCAL => { - node_struct.node.as_ref::().config() as *const _ as *const _ + node_struct.node.as_ref().local.config() as *const _ as *const _ } } } @@ -367,18 +375,13 @@ pub unsafe extern "C" fn iox2_node_drop(node_handle: iox2_node_h) { match node_struct.service_type { iox2_service_type_e::IPC => { - std::ptr::drop_in_place( - node_struct.node.as_option_mut::() as *mut _ - ); - (node_struct.deleter)(node_struct); + ManuallyDrop::drop(&mut node_struct.node.as_mut().ipc); } iox2_service_type_e::LOCAL => { - std::ptr::drop_in_place( - node_struct.node.as_option_mut::() as *mut _ - ); - (node_struct.deleter)(node_struct); + ManuallyDrop::drop(&mut node_struct.node.as_mut().local); } } + (node_struct.deleter)(node_struct); } // END C API @@ -441,10 +444,7 @@ mod test { fn basic_node_config_test() { unsafe { let node_handle = create_sut_node(); - let expected_config = (*iox2_node_t::cast(node_handle)) - .node - .as_ref::() - .config(); + let expected_config = (*iox2_node_t::cast(node_handle)).node.as_ref().ipc.config(); let config = iox2_node_config(node_handle); @@ -458,10 +458,7 @@ mod test { fn basic_node_name_test() { unsafe { let node_handle = create_sut_node(); - let expected_node_name = (*iox2_node_t::cast(node_handle)) - .node - .as_ref::() - .name(); + let expected_node_name = (*iox2_node_t::cast(node_handle)).node.as_ref().ipc.name(); assert_that!(expected_node_name.as_str(), eq("hypnotoad")); let node_name = iox2_node_name(node_handle); diff --git a/iceoryx2-ffi/ffi/src/node_builder.rs b/iceoryx2-ffi/ffi/src/node_builder.rs index edf25ef5..c9999693 100644 --- a/iceoryx2-ffi/ffi/src/node_builder.rs +++ b/iceoryx2-ffi/ffi/src/node_builder.rs @@ -14,7 +14,7 @@ use crate::{ iox2_node_h, iox2_node_name_drop, iox2_node_name_h, iox2_node_name_t, iox2_node_t, - iox2_service_type_e, IntoCInt, IOX2_OK, + iox2_service_type_e, IntoCInt, NodeUnion, IOX2_OK, }; use iceoryx2::node::NodeCreationFailure; @@ -46,9 +46,9 @@ impl IntoCInt for NodeCreationFailure { } #[repr(C)] -#[repr(align(8))] // alignment of NodeBuilder +#[repr(align(8))] // alignment of Option pub struct iox2_node_builder_storage_t { - internal: [u8; 18432], // magic number obtained with size_of::() + internal: [u8; 18432], // magic number obtained with size_of::>() } impl iox2_node_builder_storage_t { @@ -280,7 +280,7 @@ pub unsafe extern "C" fn iox2_node_builder_create( match service_type { iox2_service_type_e::IPC => match node_builder.create::() { Ok(node) => unsafe { - (*node_struct_ptr).init(service_type, node, deleter); + (*node_struct_ptr).init(service_type, NodeUnion::new_ipc(node), deleter); }, Err(error) => { return error.into_c_int(); @@ -288,7 +288,7 @@ pub unsafe extern "C" fn iox2_node_builder_create( }, iox2_service_type_e::LOCAL => match node_builder.create::() { Ok(node) => unsafe { - (*node_struct_ptr).init(service_type, node, deleter); + (*node_struct_ptr).init(service_type, NodeUnion::new_local(node), deleter); }, Err(error) => { return error.into_c_int();