Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
elBoberido committed Jul 15, 2024
1 parent ba883fe commit 2996910
Show file tree
Hide file tree
Showing 16 changed files with 186 additions and 160 deletions.
12 changes: 6 additions & 6 deletions iceoryx2-ffi/ffi-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,26 +128,26 @@ pub fn iceoryx2_ffi(args: TokenStream, input: TokenStream) -> TokenStream {
#my_struct

impl #struct_name {
pub(crate) fn as_handle(&mut self) -> #struct_h_name {
pub(super) fn as_handle(&mut self) -> #struct_h_name {
self as *mut _ as _
}
pub(crate) fn as_ref_handle(&mut self) -> #struct_ref_h_name {
pub(super) fn as_ref_handle(&mut self) -> #struct_ref_h_name {
self as *mut _ as _
}

pub(crate) fn take(&mut self) -> Option<#my_type> {
pub(super) fn take(&mut self) -> Option<#my_type> {
unsafe { self.value.as_option_mut().take() }
}

pub(crate) fn set(&mut self, value: #my_type) {
pub(super) fn set(&mut self, value: #my_type) {
unsafe { *self.value.as_option_mut() = Some(value) }
}

pub(crate) fn alloc() -> *mut #struct_name {
pub(super) fn alloc() -> *mut #struct_name {
unsafe { ::std::alloc::alloc(::std::alloc::Layout::new::<#struct_name>()) as _ }
}

pub(crate) fn dealloc(storage: *mut #struct_name) {
pub(super) fn dealloc(storage: *mut #struct_name) {
unsafe {
::std::alloc::dealloc(storage as _, ::core::alloc::Layout::new::<#struct_name>())
}
Expand Down
19 changes: 19 additions & 0 deletions iceoryx2-ffi/ffi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,22 @@ outside of this crate. The opaque types additionally need to be manually forward

- renaming is done in `[export.rename]` with `"Foo" = "iox2_foo_ptr_t"`
- forward declaration is done in the `after_includes` section with `typedef struct iox2_foo_ptr_t iox2_foo_ptr_t;`

## Why the folder structure with 'api' and 'test'

As it turned out `cdylib`s do not play well with integration tests. The `cdylib` is build
with `panic="abort"` but the tests require `panic="unwind"`. This results in building the lib
twice if there are integration tests and leads to the following warning and eventually to build failures.

> warning: output filename collision.
> The lib target `iceoryx2_ffi` in package `iceoryx2-ffi v0.3.0 (C:\Users\ekxide\iceoryx2\iceoryx2-ffi\ffi)`
> has the same output filename as the lib target `iceoryx2_ffi` in package
> `iceoryx2-ffi v0.3.0 (C:\Users\ekxide\iceoryx2\iceoryx2-ffi\ffi)`.
> Colliding filename is: C:\Users\ekxide\iceoryx2\target\release\deps\iceoryx2_ffi.lib
> The targets should have unique names.
> Consider changing their names to be unique or compiling them separately.
> This may become a hard error in the future; see <https://github.com/rust-lang/cargo/issues/6313>.
As a workaround, the integrationtests are placed in the module. This would give access to private API though. To circumvent this problem,
only `pub(super)` shall be used if an API needs to be available in other modules but not `pub(crate)`. With the chosen folder
structure the tests can again only be written as whitebox tests.
File renamed without changes.
135 changes: 135 additions & 0 deletions iceoryx2-ffi/ffi/src/api/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// Copyright (c) 2024 Contributors to the Eclipse Foundation
//
// See the NOTICE file(s) distributed with this work for additional
// information regarding copyright ownership.
//
// This program and the accompanying materials are made available under the
// terms of the Apache Software License 2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
// which is available at https://opensource.org/licenses/MIT.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT

#![allow(non_camel_case_types)]

use iceoryx2::prelude::*;
use iceoryx2_bb_container::semantic_string::SemanticStringError;
use iceoryx2_bb_log::set_log_level;

use core::ffi::c_int;

mod config;
mod node;
mod node_builder;
mod node_name;
mod publisher;
mod service;
mod service_builder;
mod subscriber;

pub use config::*;
pub use node::*;
pub use node_builder::*;
pub use node_name::*;
pub use publisher::*;
pub use service::*;
pub use service_builder::*;
pub use subscriber::*;

/// This constant signals an successful function call
pub const IOX2_OK: c_int = 0;

#[repr(C)]
#[derive(Copy, Clone)]
pub enum iox2_callback_progression_e {
STOP = 0,
CONTINUE,
}

impl From<iox2_callback_progression_e> for CallbackProgression {
fn from(value: iox2_callback_progression_e) -> Self {
match value {
iox2_callback_progression_e::STOP => CallbackProgression::Stop,
iox2_callback_progression_e::CONTINUE => CallbackProgression::Continue,
}
}
}

#[repr(C)]
#[derive(Copy, Clone)]
pub enum iox2_semantic_string_error_e {
INVALID_CONTENT = IOX2_OK as isize + 1,
EXCEEDS_MAXIMUM_LENGTH,
}

impl IntoCInt for SemanticStringError {
fn into_c_int(self) -> c_int {
(match self {
SemanticStringError::InvalidContent => iox2_semantic_string_error_e::INVALID_CONTENT,
SemanticStringError::ExceedsMaximumLength => {
iox2_semantic_string_error_e::EXCEEDS_MAXIMUM_LENGTH
}
}) as c_int
}
}

#[no_mangle]
pub extern "C" fn zero_copy_service_list() -> i32 {
set_log_level(iceoryx2_bb_log::LogLevel::Info);

let callback = |service| {
println!("\n{:#?}", service?);
Ok(CallbackProgression::Continue)
};

match zero_copy::Service::list(Config::global_config(), callback) {
Ok(_) => 0,
Err(_) => -1,
}
}

/// This is a trait to convert a Rust error enum into the corresponding C error enum and then to a c_int in one go
///
/// # Example
///
/// ```no_run
/// use core::ffi::c_int;
///
/// trait IntoCInt {
/// fn into_c_int(self) -> c_int;
/// }
///
/// enum FooError {
/// BAR,
/// BAZ
/// }
///
/// #[repr(C)]
/// #[derive(Copy, Clone)]
/// pub enum iox2_foo_error_e {
/// BAR = 1, // start at 1 since IOX2_OK is already 0
/// BAZ,
/// }
///
/// impl IntoCInt for FooError {
/// fn into_c_int(self) -> c_int {
/// (match self {
/// FooError::BAR => iox2_foo_error_e::BAR,
/// FooError::BAZ => iox2_foo_error_e::BAZ,
/// }) as c_int
/// }
/// }
/// ```
trait IntoCInt {
fn into_c_int(self) -> c_int;
}

trait HandleToType {
type Target;

// NOTE in this case, the handle `self` is already a `*mut`. Passing by value means a copy
// of the pointer; passing by reference make the implementation more error prone since one
// has to remember to de-reference `self` in order to get the `*mut`
#[allow(clippy::wrong_self_convention)]
fn as_type(self) -> Self::Target;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

#![allow(non_camel_case_types)]

use crate::{
use crate::api::{
iox2_callback_progression_e, iox2_config_ptr, iox2_node_name_ptr, iox2_service_builder_h,
iox2_service_builder_t, iox2_service_name_h, iox2_service_type_e, HandleToType, IntoCInt,
IOX2_OK,
Expand Down Expand Up @@ -48,18 +48,18 @@ impl IntoCInt for NodeListFailure {
}
}

pub(crate) union NodeUnion {
pub(super) union NodeUnion {
ipc: ManuallyDrop<Node<zero_copy::Service>>,
local: ManuallyDrop<Node<process_local::Service>>,
}

impl NodeUnion {
pub(crate) fn new_ipc(node: Node<zero_copy::Service>) -> Self {
pub(super) fn new_ipc(node: Node<zero_copy::Service>) -> Self {
Self {
ipc: ManuallyDrop::new(node),
}
}
pub(crate) fn new_local(node: Node<process_local::Service>) -> Self {
pub(super) fn new_local(node: Node<process_local::Service>) -> Self {
Self {
local: ManuallyDrop::new(node),
}
Expand All @@ -75,13 +75,13 @@ pub struct iox2_node_storage_t {
#[repr(C)]
#[iceoryx2_ffi(NodeUnion)]
pub struct iox2_node_t {
pub(crate) service_type: iox2_service_type_e,
pub(crate) value: iox2_node_storage_t,
pub(crate) deleter: fn(*mut iox2_node_t),
pub(super) service_type: iox2_service_type_e,
pub(super) value: iox2_node_storage_t,
pub(super) deleter: fn(*mut iox2_node_t),
}

impl iox2_node_t {
pub(crate) fn init(
pub(super) fn init(
&mut self,
service_type: iox2_service_type_e,
value: NodeUnion,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

#![allow(non_camel_case_types)]

use crate::{
use crate::api::{
iox2_node_h, iox2_node_name_drop, iox2_node_name_h, iox2_node_t, iox2_service_type_e,
HandleToType, IntoCInt, NodeUnion, IOX2_OK,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

#![allow(non_camel_case_types)]

use crate::{iox2_semantic_string_error_e, HandleToType, IntoCInt, IOX2_OK};
use crate::api::{iox2_semantic_string_error_e, HandleToType, IntoCInt, IOX2_OK};

use iceoryx2::prelude::*;
use iceoryx2_bb_elementary::static_assert::*;
Expand All @@ -32,7 +32,7 @@ pub struct iox2_node_name_storage_t {
#[repr(C)]
#[iceoryx2_ffi(NodeName)]
pub struct iox2_node_name_t {
value: iox2_node_name_storage_t,
pub value: iox2_node_name_storage_t,
deleter: fn(*mut iox2_node_name_t),
}

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
124 changes: 4 additions & 120 deletions iceoryx2-ffi/ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,124 +12,8 @@

#![allow(non_camel_case_types)]

use iceoryx2::prelude::*;
use iceoryx2_bb_container::semantic_string::SemanticStringError;
use iceoryx2_bb_log::set_log_level;
mod api;
pub use api::*;

use core::ffi::c_int;

mod config;
mod node;
mod node_builder;
mod node_name;
mod publisher;
mod service;
mod service_builder;
mod subscriber;

pub use config::*;
pub use node::*;
pub use node_builder::*;
pub use node_name::*;
pub use publisher::*;
pub use service::*;
pub use service_builder::*;
pub use subscriber::*;

/// This constant signals an successful function call
pub const IOX2_OK: c_int = 0;

#[repr(C)]
#[derive(Copy, Clone)]
pub enum iox2_callback_progression_e {
STOP = 0,
CONTINUE,
}

impl From<iox2_callback_progression_e> for CallbackProgression {
fn from(value: iox2_callback_progression_e) -> Self {
match value {
iox2_callback_progression_e::STOP => CallbackProgression::Stop,
iox2_callback_progression_e::CONTINUE => CallbackProgression::Continue,
}
}
}

#[repr(C)]
#[derive(Copy, Clone)]
pub enum iox2_semantic_string_error_e {
INVALID_CONTENT = IOX2_OK as isize + 1,
EXCEEDS_MAXIMUM_LENGTH,
}

impl IntoCInt for SemanticStringError {
fn into_c_int(self) -> c_int {
(match self {
SemanticStringError::InvalidContent => iox2_semantic_string_error_e::INVALID_CONTENT,
SemanticStringError::ExceedsMaximumLength => {
iox2_semantic_string_error_e::EXCEEDS_MAXIMUM_LENGTH
}
}) as c_int
}
}

#[no_mangle]
pub extern "C" fn zero_copy_service_list() -> i32 {
set_log_level(iceoryx2_bb_log::LogLevel::Info);

let callback = |service| {
println!("\n{:#?}", service?);
Ok(CallbackProgression::Continue)
};

match zero_copy::Service::list(Config::global_config(), callback) {
Ok(_) => 0,
Err(_) => -1,
}
}

/// This is a trait to convert a Rust error enum into the corresponding C error enum and then to a c_int in one go
///
/// # Example
///
/// ```no_run
/// use core::ffi::c_int;
///
/// trait IntoCInt {
/// fn into_c_int(self) -> c_int;
/// }
///
/// enum FooError {
/// BAR,
/// BAZ
/// }
///
/// #[repr(C)]
/// #[derive(Copy, Clone)]
/// pub enum iox2_foo_error_e {
/// BAR = 1, // start at 1 since IOX2_OK is already 0
/// BAZ,
/// }
///
/// impl IntoCInt for FooError {
/// fn into_c_int(self) -> c_int {
/// (match self {
/// FooError::BAR => iox2_foo_error_e::BAR,
/// FooError::BAZ => iox2_foo_error_e::BAZ,
/// }) as c_int
/// }
/// }
/// ```
trait IntoCInt {
fn into_c_int(self) -> c_int;
}

pub trait HandleToType {
type Target;

// NOTE in this case, the handle `self` is already a `*mut`. Passing by value means a copy
// of the pointer; passing by reference make the implementation more error prone since one
// has to remember to de-reference `self` in order to get the `*mut`
#[allow(clippy::wrong_self_convention)]
fn as_type(self) -> Self::Target;
}
#[cfg(test)]
mod tests;
Loading

0 comments on commit 2996910

Please sign in to comment.