iceoryx2_ffi/api/
notifier.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    c_size_t, iox2_event_id_t, iox2_service_type_e, iox2_unique_notifier_id_h,
17    iox2_unique_notifier_id_t, AssertNonNullHandle, HandleToType, IntoCInt, IOX2_OK,
18};
19
20use iceoryx2::port::notifier::{Notifier, NotifierNotifyError};
21use iceoryx2::prelude::*;
22use iceoryx2_bb_elementary::static_assert::*;
23use iceoryx2_ffi_macros::iceoryx2_ffi;
24
25use core::ffi::c_int;
26use core::mem::ManuallyDrop;
27
28// BEGIN types definition
29
30#[repr(C)]
31#[derive(Copy, Clone)]
32pub enum iox2_notifier_notify_error_e {
33    EVENT_ID_OUT_OF_BOUNDS = IOX2_OK as isize + 1,
34}
35
36impl IntoCInt for NotifierNotifyError {
37    fn into_c_int(self) -> c_int {
38        (match self {
39            NotifierNotifyError::EventIdOutOfBounds => {
40                iox2_notifier_notify_error_e::EVENT_ID_OUT_OF_BOUNDS
41            }
42        }) as c_int
43    }
44}
45
46pub(super) union NotifierUnion {
47    ipc: ManuallyDrop<Notifier<ipc::Service>>,
48    local: ManuallyDrop<Notifier<local::Service>>,
49}
50
51impl NotifierUnion {
52    pub(super) fn new_ipc(notifier: Notifier<ipc::Service>) -> Self {
53        Self {
54            ipc: ManuallyDrop::new(notifier),
55        }
56    }
57    pub(super) fn new_local(notifier: Notifier<local::Service>) -> Self {
58        Self {
59            local: ManuallyDrop::new(notifier),
60        }
61    }
62}
63
64#[repr(C)]
65#[repr(align(8))] // alignment of Option<NotifierUnion>
66pub struct iox2_notifier_storage_t {
67    internal: [u8; 1656], // magic number obtained with size_of::<Option<NotifierUnion>>()
68}
69
70#[repr(C)]
71#[iceoryx2_ffi(NotifierUnion)]
72pub struct iox2_notifier_t {
73    service_type: iox2_service_type_e,
74    value: iox2_notifier_storage_t,
75    deleter: fn(*mut iox2_notifier_t),
76}
77
78impl iox2_notifier_t {
79    pub(super) fn init(
80        &mut self,
81        service_type: iox2_service_type_e,
82        value: NotifierUnion,
83        deleter: fn(*mut iox2_notifier_t),
84    ) {
85        self.service_type = service_type;
86        self.value.init(value);
87        self.deleter = deleter;
88    }
89}
90
91pub struct iox2_notifier_h_t;
92/// The owning handle for `iox2_notifier_t`. Passing the handle to an function transfers the ownership.
93pub type iox2_notifier_h = *mut iox2_notifier_h_t;
94/// The non-owning handle for `iox2_notifier_t`. Passing the handle to an function does not transfers the ownership.
95pub type iox2_notifier_h_ref = *const iox2_notifier_h;
96
97impl AssertNonNullHandle for iox2_notifier_h {
98    fn assert_non_null(self) {
99        debug_assert!(!self.is_null());
100    }
101}
102
103impl AssertNonNullHandle for iox2_notifier_h_ref {
104    fn assert_non_null(self) {
105        debug_assert!(!self.is_null());
106        unsafe {
107            debug_assert!(!(*self).is_null());
108        }
109    }
110}
111
112impl HandleToType for iox2_notifier_h {
113    type Target = *mut iox2_notifier_t;
114
115    fn as_type(self) -> Self::Target {
116        self as *mut _ as _
117    }
118}
119
120impl HandleToType for iox2_notifier_h_ref {
121    type Target = *mut iox2_notifier_t;
122
123    fn as_type(self) -> Self::Target {
124        unsafe { *self as *mut _ as _ }
125    }
126}
127
128// END type definition
129
130// BEGIN C API
131
132/// Returns the unique port id of the notifier.
133///
134/// # Safety
135///
136/// * `notifier_handle` is valid, non-null and was obtained via [`iox2_port_factory_notifier_builder_create`](crate::iox2_port_factory_notifier_builder_create).
137/// * `id_struct_ptr` - Must be either a NULL pointer or a pointer to a valid [`iox2_unique_notifier_id_t`].
138///                         If it is a NULL pointer, the storage will be allocated on the heap.
139/// * `id_handle_ptr` valid pointer to a [`iox2_unique_notifier_id_h`].
140#[no_mangle]
141pub unsafe extern "C" fn iox2_notifier_id(
142    notifier_handle: iox2_notifier_h_ref,
143    id_struct_ptr: *mut iox2_unique_notifier_id_t,
144    id_handle_ptr: *mut iox2_unique_notifier_id_h,
145) {
146    notifier_handle.assert_non_null();
147    debug_assert!(!id_handle_ptr.is_null());
148
149    fn no_op(_: *mut iox2_unique_notifier_id_t) {}
150    let mut deleter: fn(*mut iox2_unique_notifier_id_t) = no_op;
151    let mut storage_ptr = id_struct_ptr;
152    if id_struct_ptr.is_null() {
153        deleter = iox2_unique_notifier_id_t::dealloc;
154        storage_ptr = iox2_unique_notifier_id_t::alloc();
155    }
156    debug_assert!(!storage_ptr.is_null());
157
158    let notifier = &mut *notifier_handle.as_type();
159
160    let id = match notifier.service_type {
161        iox2_service_type_e::IPC => notifier.value.as_mut().ipc.id(),
162        iox2_service_type_e::LOCAL => notifier.value.as_mut().local.id(),
163    };
164
165    (*storage_ptr).init(id, deleter);
166    *id_handle_ptr = (*storage_ptr).as_handle();
167}
168
169/// Notifies all [`iox2_listener_h`](crate::iox2_listener_h) connected to the service
170/// with the default event id provided on creation.
171///
172/// # Arguments
173///
174/// * notifier_handle -  Must be a valid [`iox2_notifier_h_ref`]
175///   obtained by [`iox2_port_factory_notifier_builder_create`](crate::iox2_port_factory_notifier_builder_create)
176/// * number_of_notified_listener_ptr - Must be either a NULL pointer or a pointer to a `size_t` to store the number of notified listener
177///
178/// Returns IOX2_OK on success, an [`iox2_notifier_notify_error_e`] otherwise.
179///
180/// # Safety
181///
182/// `notifier_handle` must be a valid handle and is still valid after the return of this function and can be use in another function call.
183#[no_mangle]
184pub unsafe extern "C" fn iox2_notifier_notify(
185    notifier_handle: iox2_notifier_h_ref,
186    number_of_notified_listener_ptr: *mut c_size_t,
187) -> c_int {
188    notifier_handle.assert_non_null();
189
190    let notifier = &mut *notifier_handle.as_type();
191
192    let notify_result = match notifier.service_type {
193        iox2_service_type_e::IPC => notifier.value.as_mut().ipc.notify(),
194        iox2_service_type_e::LOCAL => notifier.value.as_mut().local.notify(),
195    };
196
197    match notify_result {
198        Ok(count) => {
199            if !number_of_notified_listener_ptr.is_null() {
200                *number_of_notified_listener_ptr = count;
201            }
202        }
203        Err(error) => {
204            return error.into_c_int();
205        }
206    }
207
208    IOX2_OK
209}
210
211/// Notifies all [`iox2_listener_h`](crate::iox2_listener_h) connected to the service
212/// with the custom event id.
213///
214/// # Arguments
215///
216/// * notifier_handle -  Must be a valid [`iox2_notifier_h_ref`]
217///   obtained by [`iox2_port_factory_notifier_builder_create`](crate::iox2_port_factory_notifier_builder_create)
218/// * custom_event_id_ptr - Must be a pointer to an initialized [`iox2_event_id_t`](crate::iox2_event_id_t)
219/// * number_of_notified_listener_ptr - Must be either a NULL pointer or a pointer to a `size_t` to store the number of notified listener
220///
221/// Returns IOX2_OK on success, an [`iox2_notifier_notify_error_e`] otherwise.
222///
223/// # Safety
224///
225/// `notifier_handle` must be a valid handle and is still valid after the return of this function and can be use in another function call.
226/// `custom_event_id_ptr` must not be a NULL pointer.
227#[no_mangle]
228pub unsafe extern "C" fn iox2_notifier_notify_with_custom_event_id(
229    notifier_handle: iox2_notifier_h_ref,
230    custom_event_id_ptr: *const iox2_event_id_t,
231    number_of_notified_listener_ptr: *mut c_size_t,
232) -> c_int {
233    notifier_handle.assert_non_null();
234    debug_assert!(!custom_event_id_ptr.is_null());
235
236    let event_id = (*custom_event_id_ptr).into();
237
238    let notifier = &mut *notifier_handle.as_type();
239    let notify_result = match notifier.service_type {
240        iox2_service_type_e::IPC => notifier
241            .value
242            .as_mut()
243            .ipc
244            .notify_with_custom_event_id(event_id),
245        iox2_service_type_e::LOCAL => notifier
246            .value
247            .as_mut()
248            .local
249            .notify_with_custom_event_id(event_id),
250    };
251
252    match notify_result {
253        Ok(count) => {
254            if !number_of_notified_listener_ptr.is_null() {
255                *number_of_notified_listener_ptr = count;
256            }
257        }
258        Err(error) => {
259            return error.into_c_int();
260        }
261    }
262
263    IOX2_OK
264}
265
266/// This function needs to be called to destroy the notifier!
267///
268/// # Arguments
269///
270/// * `notifier_handle` - A valid [`iox2_notifier_h`]
271///
272/// # Safety
273///
274/// * The `notifier_handle` is invalid after the return of this function and leads to undefined behavior if used in another function call!
275/// * The corresponding [`iox2_notifier_t`] can be re-used with a call to
276///   [`iox2_port_factory_notifier_builder_create`](crate::iox2_port_factory_notifier_builder_create)!
277#[no_mangle]
278pub unsafe extern "C" fn iox2_notifier_drop(notifier_handle: iox2_notifier_h) {
279    debug_assert!(!notifier_handle.is_null());
280
281    let notifier = &mut *notifier_handle.as_type();
282
283    match notifier.service_type {
284        iox2_service_type_e::IPC => {
285            ManuallyDrop::drop(&mut notifier.value.as_mut().ipc);
286        }
287        iox2_service_type_e::LOCAL => {
288            ManuallyDrop::drop(&mut notifier.value.as_mut().local);
289        }
290    }
291    (notifier.deleter)(notifier);
292}
293
294// END C API