iceoryx2_ffi/api/
node_builder.rs

1// Copyright (c) 2024 Contributors to the Eclipse Foundation
2//
3// See the NOTICE file(s) distributed with this work for additional
4// information regarding copyright ownership.
5//
6// This program and the accompanying materials are made available under the
7// terms of the Apache Software License 2.0 which is available at
8// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
9// which is available at https://opensource.org/licenses/MIT.
10//
11// SPDX-License-Identifier: Apache-2.0 OR MIT
12
13#![allow(non_camel_case_types)]
14
15use crate::api::{
16    iox2_config_h_ref, iox2_node_h, iox2_node_name_ptr, iox2_node_t, iox2_service_type_e,
17    AssertNonNullHandle, HandleToType, IntoCInt, NodeUnion, IOX2_OK,
18};
19
20use iceoryx2::node::NodeCreationFailure;
21use iceoryx2::prelude::*;
22use iceoryx2_bb_elementary::static_assert::*;
23use iceoryx2_bb_log::fatal_panic;
24use iceoryx2_ffi_macros::iceoryx2_ffi;
25
26use core::ffi::c_int;
27
28// BEGIN types definition
29
30#[repr(C)]
31#[derive(Copy, Clone)]
32pub enum iox2_node_creation_failure_e {
33    INSUFFICIENT_PERMISSIONS = IOX2_OK as isize + 1,
34    INTERNAL_ERROR,
35}
36
37impl IntoCInt for NodeCreationFailure {
38    fn into_c_int(self) -> c_int {
39        (match self {
40            NodeCreationFailure::InsufficientPermissions => {
41                iox2_node_creation_failure_e::INSUFFICIENT_PERMISSIONS
42            }
43            NodeCreationFailure::InternalError => iox2_node_creation_failure_e::INTERNAL_ERROR,
44        }) as c_int
45    }
46}
47
48#[repr(C)]
49#[repr(align(8))] // alignment of Option<NodeBuilder>
50pub struct iox2_node_builder_storage_t {
51    internal: [u8; 18696], // magic number obtained with size_of::<NodeBuilder>()
52}
53
54#[repr(C)]
55#[iceoryx2_ffi(NodeBuilder)]
56pub struct iox2_node_builder_t {
57    value: iox2_node_builder_storage_t,
58    deleter: fn(*mut iox2_node_builder_t),
59}
60
61pub struct iox2_node_builder_h_t;
62/// The owning handle for `iox2_node_builder_t`. Passing the handle to an function transfers the ownership.
63pub type iox2_node_builder_h = *mut iox2_node_builder_h_t;
64/// The non-owning handle for `iox2_node_builder_t`. Passing the handle to an function does not transfers the ownership.
65pub type iox2_node_builder_h_ref = *const iox2_node_builder_h;
66
67impl AssertNonNullHandle for iox2_node_builder_h {
68    fn assert_non_null(self) {
69        debug_assert!(!self.is_null());
70    }
71}
72
73impl AssertNonNullHandle for iox2_node_builder_h_ref {
74    fn assert_non_null(self) {
75        debug_assert!(!self.is_null());
76        unsafe {
77            debug_assert!(!(*self).is_null());
78        }
79    }
80}
81
82impl HandleToType for iox2_node_builder_h {
83    type Target = *mut iox2_node_builder_t;
84
85    fn as_type(self) -> Self::Target {
86        self as *mut _ as _
87    }
88}
89
90impl HandleToType for iox2_node_builder_h_ref {
91    type Target = *mut iox2_node_builder_t;
92
93    fn as_type(self) -> Self::Target {
94        unsafe { *self as *mut _ as _ }
95    }
96}
97
98// END type definition
99
100// BEGIN C API
101
102/// Creates a builder for nodes
103///
104/// # Arguments
105///
106/// * `node_builder_struct_ptr` - Must be either a NULL pointer or a pointer to a valid [`iox2_node_builder_t`]. If it is a NULL pointer, the storage will be allocated on the heap.
107///
108/// # Returns
109///
110/// A [`iox2_node_builder_h`] handle to build the actual node.
111///
112/// # Safety
113///
114/// * The same [`iox2_node_builder_t`] cannot be used in subsequent calls to this function, unless [`iox2_node_builder_create`] was called before!
115#[no_mangle]
116pub unsafe extern "C" fn iox2_node_builder_new(
117    node_builder_struct_ptr: *mut iox2_node_builder_t,
118) -> iox2_node_builder_h {
119    let mut node_builder_struct_ptr = node_builder_struct_ptr;
120    fn no_op(_: *mut iox2_node_builder_t) {}
121    let mut deleter: fn(*mut iox2_node_builder_t) = no_op;
122    if node_builder_struct_ptr.is_null() {
123        node_builder_struct_ptr = iox2_node_builder_t::alloc();
124        deleter = iox2_node_builder_t::dealloc;
125    }
126    debug_assert!(!node_builder_struct_ptr.is_null());
127
128    (*node_builder_struct_ptr).deleter = deleter;
129    (*node_builder_struct_ptr).value.init(NodeBuilder::new());
130
131    (*node_builder_struct_ptr).as_handle()
132}
133
134/// Sets the node name for the builder
135///
136/// # Arguments
137///
138/// * `node_builder_handle` - Must be a valid [`iox2_node_builder_h_ref`] obtained by [`iox2_node_builder_new`].
139/// * `node_name_ptr` - Must be a valid [`iox2_node_name_ptr`], e.g. obtained by [`iox2_node_name_new`](crate::iox2_node_name_new) and converted
140///    by [`iox2_cast_node_name_ptr`](crate::iox2_cast_node_name_ptr)
141///
142/// Returns IOX2_OK
143///
144/// # Safety
145///
146/// * `node_builder_handle` as well as `node_name_ptr` must be valid handles
147#[no_mangle]
148pub unsafe extern "C" fn iox2_node_builder_set_name(
149    node_builder_handle: iox2_node_builder_h_ref,
150    node_name_ptr: iox2_node_name_ptr,
151) -> c_int {
152    node_builder_handle.assert_non_null();
153    debug_assert!(!node_name_ptr.is_null());
154
155    let node_builder_struct = &mut *node_builder_handle.as_type();
156
157    let node_builder = node_builder_struct.take().unwrap();
158    let node_builder = node_builder.name(&*node_name_ptr);
159    node_builder_struct.set(node_builder);
160
161    IOX2_OK
162}
163
164/// Sets the node config for the builder
165///
166/// Returns IOX2_OK
167///
168/// # Safety
169///
170/// * `node_builder_handle` - Must be a valid [`iox2_node_builder_h_ref`] obtained by [`iox2_node_builder_new`].
171/// * `config_handle` - Must be a valid [`iox2_config_h_ref`]
172///
173#[no_mangle]
174pub unsafe extern "C" fn iox2_node_builder_set_config(
175    node_builder_handle: iox2_node_builder_h_ref,
176    config_handle: iox2_config_h_ref,
177) {
178    node_builder_handle.assert_non_null();
179    config_handle.assert_non_null();
180
181    let node_builder_struct = &mut *node_builder_handle.as_type();
182    let config = &*config_handle.as_type();
183
184    let node_builder = node_builder_struct.take().unwrap();
185    let node_builder = node_builder.config(&config.value.as_ref().value);
186    node_builder_struct.set(node_builder);
187}
188
189// intentionally not public API
190unsafe fn iox2_node_builder_drop(node_builder_handle: iox2_node_builder_h) {
191    debug_assert!(!node_builder_handle.is_null());
192
193    let node_builder = &mut *node_builder_handle.as_type();
194    std::ptr::drop_in_place(node_builder.value.as_option_mut());
195    (node_builder.deleter)(node_builder);
196}
197
198/// Creates a node and consumes the builder
199///
200/// # Arguments
201///
202/// * `node_builder_handle` - Must be a valid [`iox2_node_builder_h`] obtained by [`iox2_node_builder_new`].
203/// * `node_struct_ptr` - Must be either a NULL pointer or a pointer to a valid [`iox2_node_t`]. If it is a NULL pointer, the storage will be allocated on the heap.
204/// * `service_type` - The [`iox2_service_type_e`] for the node to be created.
205/// * `node_handle_ptr` - An uninitialized or dangling [`iox2_node_h`] handle which will be initialized by this function call.
206///
207/// Returns IOX2_OK on success, an [`iox2_node_creation_failure_e`] otherwise.
208///
209/// # Safety
210///
211/// * The `node_builder_handle` is invalid after the return of this function and leads to undefined behavior if used in another function call!
212/// * The corresponding [`iox2_node_builder_t`] can be re-used with a call to [`iox2_node_builder_new`]!
213#[no_mangle]
214pub unsafe extern "C" fn iox2_node_builder_create(
215    node_builder_handle: iox2_node_builder_h,
216    node_struct_ptr: *mut iox2_node_t,
217    service_type: iox2_service_type_e,
218    node_handle_ptr: *mut iox2_node_h,
219) -> c_int {
220    debug_assert!(!node_builder_handle.is_null());
221    debug_assert!(!node_handle_ptr.is_null());
222
223    match service_type as usize {
224        0 => (),
225        1 => (),
226        _ => fatal_panic!(from "iox2_node_builder_create",
227                            "The provided service_type has an invalid value."),
228    }
229
230    let node_builder_struct = &mut *node_builder_handle.as_type();
231    let node_builder = node_builder_struct.take().unwrap();
232    iox2_node_builder_drop(node_builder_handle);
233
234    let mut node_struct_ptr = node_struct_ptr;
235    fn no_op(_: *mut iox2_node_t) {}
236    let mut deleter: fn(*mut iox2_node_t) = no_op;
237    if node_struct_ptr.is_null() {
238        node_struct_ptr = iox2_node_t::alloc();
239        deleter = iox2_node_t::dealloc;
240    }
241    debug_assert!(!node_struct_ptr.is_null());
242
243    match service_type {
244        iox2_service_type_e::IPC => match node_builder.create::<ipc::Service>() {
245            Ok(node) => unsafe {
246                (*node_struct_ptr).init(service_type, NodeUnion::new_ipc(node), deleter);
247            },
248            Err(error) => {
249                return error.into_c_int();
250            }
251        },
252        iox2_service_type_e::LOCAL => match node_builder.create::<local::Service>() {
253            Ok(node) => unsafe {
254                (*node_struct_ptr).init(service_type, NodeUnion::new_local(node), deleter);
255            },
256            Err(error) => {
257                return error.into_c_int();
258            }
259        },
260    }
261
262    *node_handle_ptr = (*node_struct_ptr).as_handle();
263
264    IOX2_OK
265}
266
267// END C API