iceoryx2_ffi/api/
port_factory_notifier_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_event_id_t, iox2_notifier_h, iox2_notifier_t, iox2_service_type_e, AssertNonNullHandle,
17    HandleToType, IntoCInt, NotifierUnion, IOX2_OK,
18};
19
20use iceoryx2::port::notifier::NotifierCreateError;
21use iceoryx2::prelude::*;
22use iceoryx2::service::port_factory::notifier::PortFactoryNotifier;
23use iceoryx2_bb_elementary::static_assert::*;
24use iceoryx2_ffi_macros::iceoryx2_ffi;
25
26use core::ffi::c_int;
27use core::mem::ManuallyDrop;
28
29// BEGIN types definition
30
31#[repr(C)]
32#[derive(Copy, Clone)]
33pub enum iox2_notifier_create_error_e {
34    EXCEEDS_MAX_SUPPORTED_NOTIFIERS = IOX2_OK as isize + 1,
35}
36
37impl IntoCInt for NotifierCreateError {
38    fn into_c_int(self) -> c_int {
39        (match self {
40            NotifierCreateError::ExceedsMaxSupportedNotifiers => {
41                iox2_notifier_create_error_e::EXCEEDS_MAX_SUPPORTED_NOTIFIERS
42            }
43        }) as c_int
44    }
45}
46
47pub(super) union PortFactoryNotifierBuilderUnion {
48    ipc: ManuallyDrop<PortFactoryNotifier<'static, ipc::Service>>,
49    local: ManuallyDrop<PortFactoryNotifier<'static, local::Service>>,
50}
51
52impl PortFactoryNotifierBuilderUnion {
53    pub(super) fn new_ipc(port_factory: PortFactoryNotifier<'static, ipc::Service>) -> Self {
54        Self {
55            ipc: ManuallyDrop::new(port_factory),
56        }
57    }
58    pub(super) fn new_local(port_factory: PortFactoryNotifier<'static, local::Service>) -> Self {
59        Self {
60            local: ManuallyDrop::new(port_factory),
61        }
62    }
63}
64
65#[repr(C)]
66#[repr(align(8))] // alignment of Option<PortFactoryNotifierBuilderUnion>
67pub struct iox2_port_factory_notifier_builder_storage_t {
68    internal: [u8; 24], // magic number obtained with size_of::<Option<PortFactoryNotifierBuilderUnion>>()
69}
70
71#[repr(C)]
72#[iceoryx2_ffi(PortFactoryNotifierBuilderUnion)]
73pub struct iox2_port_factory_notifier_builder_t {
74    service_type: iox2_service_type_e,
75    value: iox2_port_factory_notifier_builder_storage_t,
76    deleter: fn(*mut iox2_port_factory_notifier_builder_t),
77}
78
79impl iox2_port_factory_notifier_builder_t {
80    pub(super) fn init(
81        &mut self,
82        service_type: iox2_service_type_e,
83        value: PortFactoryNotifierBuilderUnion,
84        deleter: fn(*mut iox2_port_factory_notifier_builder_t),
85    ) {
86        self.service_type = service_type;
87        self.value.init(value);
88        self.deleter = deleter;
89    }
90}
91
92pub struct iox2_port_factory_notifier_builder_h_t;
93/// The owning handle for `iox2_port_factory_notifier_builder_t`. Passing the handle to an function transfers the ownership.
94pub type iox2_port_factory_notifier_builder_h = *mut iox2_port_factory_notifier_builder_h_t;
95/// The non-owning handle for `iox2_port_factory_notifier_builder_t`. Passing the handle to an function does not transfers the ownership.
96pub type iox2_port_factory_notifier_builder_h_ref = *const iox2_port_factory_notifier_builder_h;
97
98impl AssertNonNullHandle for iox2_port_factory_notifier_builder_h {
99    fn assert_non_null(self) {
100        debug_assert!(!self.is_null());
101    }
102}
103
104impl AssertNonNullHandle for iox2_port_factory_notifier_builder_h_ref {
105    fn assert_non_null(self) {
106        debug_assert!(!self.is_null());
107        unsafe {
108            debug_assert!(!(*self).is_null());
109        }
110    }
111}
112
113impl HandleToType for iox2_port_factory_notifier_builder_h {
114    type Target = *mut iox2_port_factory_notifier_builder_t;
115
116    fn as_type(self) -> Self::Target {
117        self as *mut _ as _
118    }
119}
120
121impl HandleToType for iox2_port_factory_notifier_builder_h_ref {
122    type Target = *mut iox2_port_factory_notifier_builder_t;
123
124    fn as_type(self) -> Self::Target {
125        unsafe { *self as *mut _ as _ }
126    }
127}
128
129// END type definition
130
131// BEGIN C API
132
133/// Sets the default event id for the builder
134///
135/// # Arguments
136///
137/// * `port_factory_handle` - Must be a valid [`iox2_port_factory_notifier_builder_h_ref`]
138///   obtained by [`iox2_port_factory_event_notifier_builder`](crate::iox2_port_factory_event_notifier_builder).
139/// * `value` - The value to set the default event id to
140///
141/// # Safety
142///
143/// * `port_factory_handle` must be valid handles
144/// * `value` must not be a NULL pointer but a pointer to an initialized `iox2_event_id_t`
145#[no_mangle]
146pub unsafe extern "C" fn iox2_port_factory_notifier_builder_set_default_event_id(
147    port_factory_handle: iox2_port_factory_notifier_builder_h_ref,
148    value: *const iox2_event_id_t,
149) {
150    port_factory_handle.assert_non_null();
151
152    let value = (*value).into();
153
154    let port_factory_struct = unsafe { &mut *port_factory_handle.as_type() };
155    match port_factory_struct.service_type {
156        iox2_service_type_e::IPC => {
157            let port_factory = ManuallyDrop::take(&mut port_factory_struct.value.as_mut().ipc);
158
159            port_factory_struct.set(PortFactoryNotifierBuilderUnion::new_ipc(
160                port_factory.default_event_id(value),
161            ));
162        }
163        iox2_service_type_e::LOCAL => {
164            let port_factory = ManuallyDrop::take(&mut port_factory_struct.value.as_mut().local);
165
166            port_factory_struct.set(PortFactoryNotifierBuilderUnion::new_local(
167                port_factory.default_event_id(value),
168            ));
169        }
170    }
171}
172
173/// Creates a notifier and consumes the builder
174///
175/// # Arguments
176///
177/// * `port_factory_handle` - Must be a valid [`iox2_port_factory_notifier_builder_h`] obtained by [`iox2_port_factory_event_notifier_builder`](crate::iox2_port_factory_event_notifier_builder).
178/// * `notifier_struct_ptr` - Must be either a NULL pointer or a pointer to a valid [`iox2_notifier_t`]. If it is a NULL pointer, the storage will be allocated on the heap.
179/// * `notifier_handle_ptr` - An uninitialized or dangling [`iox2_notifier_h`] handle which will be initialized by this function call.
180///
181/// Returns IOX2_OK on success, an [`iox2_notifier_create_error_e`] otherwise.
182///
183/// # Safety
184///
185/// * The `port_factory_handle` is invalid after the return of this function and leads to undefined behavior if used in another function call!
186/// * The corresponding [`iox2_port_factory_notifier_builder_t`]
187///   can be re-used with a call to  [`iox2_port_factory_event_notifier_builder`](crate::iox2_port_factory_event_notifier_builder)!
188#[no_mangle]
189pub unsafe extern "C" fn iox2_port_factory_notifier_builder_create(
190    port_factory_handle: iox2_port_factory_notifier_builder_h,
191    notifier_struct_ptr: *mut iox2_notifier_t,
192    notifier_handle_ptr: *mut iox2_notifier_h,
193) -> c_int {
194    debug_assert!(!port_factory_handle.is_null());
195    debug_assert!(!notifier_handle_ptr.is_null());
196
197    let mut notifier_struct_ptr = notifier_struct_ptr;
198    fn no_op(_: *mut iox2_notifier_t) {}
199    let mut deleter: fn(*mut iox2_notifier_t) = no_op;
200    if notifier_struct_ptr.is_null() {
201        notifier_struct_ptr = iox2_notifier_t::alloc();
202        deleter = iox2_notifier_t::dealloc;
203    }
204    debug_assert!(!notifier_struct_ptr.is_null());
205
206    let notifier_builder_struct = unsafe { &mut *port_factory_handle.as_type() };
207    let service_type = notifier_builder_struct.service_type;
208    let notifier_builder = notifier_builder_struct
209        .value
210        .as_option_mut()
211        .take()
212        .unwrap_or_else(|| {
213            panic!("Trying to use an invalid 'iox2_port_factory_notifier_builder_h'!")
214        });
215    (notifier_builder_struct.deleter)(notifier_builder_struct);
216
217    match service_type {
218        iox2_service_type_e::IPC => {
219            let notifier_builder = ManuallyDrop::into_inner(notifier_builder.ipc);
220
221            match notifier_builder.create() {
222                Ok(notifier) => {
223                    (*notifier_struct_ptr).init(
224                        service_type,
225                        NotifierUnion::new_ipc(notifier),
226                        deleter,
227                    );
228                }
229                Err(error) => {
230                    return error.into_c_int();
231                }
232            }
233        }
234        iox2_service_type_e::LOCAL => {
235            let notifier_builder = ManuallyDrop::into_inner(notifier_builder.local);
236
237            match notifier_builder.create() {
238                Ok(notifier) => {
239                    (*notifier_struct_ptr).init(
240                        service_type,
241                        NotifierUnion::new_local(notifier),
242                        deleter,
243                    );
244                }
245                Err(error) => {
246                    return error.into_c_int();
247                }
248            }
249        }
250    }
251
252    *notifier_handle_ptr = (*notifier_struct_ptr).as_handle();
253
254    IOX2_OK
255}
256
257// END C API