Skip to content

Commit

Permalink
Merge pull request #506 from orecham/iox2-491-cxx-api-for-error-descr…
Browse files Browse the repository at this point in the history
…iption-string

[#491] Propagate error strings from iceoryx2 via CXX API
  • Loading branch information
orecham authored Nov 20, 2024
2 parents 2bfd0c9 + 7e17337 commit 0c3b189
Show file tree
Hide file tree
Showing 40 changed files with 1,733 additions and 61 deletions.
2 changes: 1 addition & 1 deletion Cargo.Bazel.lock
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"checksum": "d7b1759c5d28cbeb3fff8b9da5ca81261aa8c593891b9eff7d3c554d07b4c8dd",
"checksum": "8c7bf9445e9dc6b2654902f1a47db51d487887849c7db5b8cb0e4e4f3ab30945",
"crates": {
"addr2line 0.24.2": {
"name": "addr2line",
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions MODULE.bazel.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion doc/release-notes/iceoryx2-unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* Developer permissions for resources [#460](https://github.com/eclipse-iceoryx/iceoryx2/issues/460)
* Add `--send-copy` flag to Benchmark to consider mem operations [#483](https://github.com/eclipse-iceoryx/iceoryx2/issues/483)
* Support for slices in the C++ bindings [#490](https://github.com/eclipse-iceoryx/iceoryx2/issues/490)
* Add API to retrieve string description of error enums [$491](https://github.com/eclipse-iceoryx/iceoryx2/issues/491)
* Add relocatable `SlotMap` [#504](https://github.com/eclipse-iceoryx/iceoryx2/issues/504)

### Bugfixes
Expand Down Expand Up @@ -59,10 +60,13 @@
conflicts when merging.
-->

* APIs to support slices in the C++ bindings [#490](https://github.com/eclipse-iceoryx/iceoryx2/issues/490)
* APIs to support slices in the C/C++ bindings [#490](https://github.com/eclipse-iceoryx/iceoryx2/issues/490)
* Rename `iox2_publisher_loan` to `iox2_publisher_loan_slice_uninit` [#490](https://github.com/eclipse-iceoryx/iceoryx2/issues/490)
1. C always loans slices, for a single element, specify the
`number_of_elements` to be 1
* Add APIs to C/C++ bindings to get string representation of error enum [#491](https://github.com/eclipse-iceoryx/iceoryx2/issues/491)
1. C API: `iox2_{error_enum_name}_string(enum_value)`
2. C++ API: `iox::into<const char*>(enum_value)`
* APIs to retrieve the value of `UniquePortIds` from the C/C++ bindings [#500](https://github.com/eclipse-iceoryx/iceoryx2/issues/500)

### API Breaking Changes
Expand Down
124 changes: 123 additions & 1 deletion iceoryx2-bb/derive-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
extern crate proc_macro;

use proc_macro::TokenStream;
use proc_macro2::Literal;
use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput, Fields};
use syn::{parse_macro_input, Data, DeriveInput, Expr, ExprLit, Fields, Lit};

/// Implements the [`iceoryx2_bb_elementary::placement_default::PlacementDefault`] trait when all
/// fields of the struct implement it.
Expand Down Expand Up @@ -99,3 +100,124 @@ pub fn placement_default_derive(input: TokenStream) -> TokenStream {

TokenStream::from(expanded)
}

/// Implements the [`iceoryx2_bb_elementary::AsStringLiteral`] trait for enums to provide a string representation of each enum variant.
///
/// The string representation can be customized using the `CustomString` attribute, otherwise it will
/// convert the variant name to lowercase and replace underscores with spaces.
///
/// # Example
/// ```
/// use iceoryx2_bb_derive_macros::StringLiteral;
/// use iceoryx2_bb_elementary::AsStringLiteral;
///
/// #[derive(StringLiteral)]
/// enum MyEnum {
/// #[CustomString = "custom variant one"]
/// VariantOne,
/// VariantTwo,
/// }
///
/// let v1 = MyEnum::VariantOne;
/// assert_eq!(v1.as_str_literal(), "custom variant one");
///
/// let v2 = MyEnum::VariantTwo;
/// assert_eq!(v2.as_str_literal(), "variant two");
/// ```
#[proc_macro_derive(StringLiteral, attributes(CustomString))]
pub fn string_literal_derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = &input.ident;
let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();

// Generate implementation converting enums to a string representation
let as_string_literal_impl = match input.data {
Data::Enum(ref data_enum) => {
let enum_to_string_mapping = data_enum.variants.iter().map(|variant| {
let enum_name = &variant.ident;
let enum_string_literal = variant
.attrs
.iter()
.find_map(|attr| {
if !attr.path().is_ident("CustomString") {
return None;
}
// Get the value of CustomString as a string literal
match attr.meta.require_name_value() {
Ok(meta) => match &meta.value {
Expr::Lit(ExprLit {
lit: Lit::Str(lit), ..
}) => Some(Literal::string(&lit.value())),
_ => None,
},
_ => None,
}
})
.unwrap_or_else(|| {
// If no CustomString, generates default string literal in the form
// MyEnum::MyVariantName => 'my variant name'
let enum_string_literal = enum_name
.to_string()
.chars()
.fold(String::new(), |mut acc, c| {
if c.is_uppercase() && !acc.is_empty() {
acc.push('_');
}
acc.push(c);
acc
})
.chars()
.map(|c| match c {
'_' => ' ',
c => c.to_ascii_lowercase(),
})
.collect::<String>();
Literal::string(&enum_string_literal)
});

// Maps each enum variant to its string representation
match &variant.fields {
Fields::Unit => {
quote! {
Self::#enum_name => #enum_string_literal
}
}
Fields::Unnamed(_) => {
quote! {
Self::#enum_name(..) => #enum_string_literal
}
}
Fields::Named(_) => {
quote! {
Self::#enum_name{..} => #enum_string_literal
}
}
}
});

// Generate the mapping for the enum variant
quote! {
fn as_str_literal(&self) -> &'static str {
match self {
#(#enum_to_string_mapping,)*
}
}
}
}
_ => {
// Does not work for non-enum types
let err =
syn::Error::new_spanned(&input, "AsStringLiteral can only be derived for enums");
return err.to_compile_error().into();
}
};

// Implement the trait with the generated implementation
let expanded = quote! {
impl #impl_generics AsStringLiteral for #name #type_generics #where_clause {
#as_string_literal_impl
}
};

TokenStream::from(expanded)
}
15 changes: 15 additions & 0 deletions iceoryx2-bb/elementary/src/as_string_literal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// 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

pub trait AsStringLiteral {
fn as_str_literal(&self) -> &'static str;
}
5 changes: 4 additions & 1 deletion iceoryx2-bb/elementary/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@
#[macro_use]
pub mod enum_gen;

/// A strong type that represents the alignment part of [`std::alloc::Layout`]
mod as_string_literal;
pub use as_string_literal::*;

pub mod alignment;
pub mod allocator;
/// A strong type that represents the alignment part of [`std::alloc::Layout`]
pub mod bump_allocator;
pub mod generic_pointer;
pub mod lazy_singleton;
Expand Down
1 change: 1 addition & 0 deletions iceoryx2-ffi/cxx/include/iox2/config_creation_error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ enum class ConfigCreationError : uint8_t {
/// Parts of the config file could not be deserialized. Indicates some kind of syntax error.
UnableToDeserializeContents
};

} // namespace iox2

#endif
1 change: 1 addition & 0 deletions iceoryx2-ffi/cxx/include/iox2/connection_failure.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ enum class ConnectionFailure : uint8_t {
/// Failures when mapping the corresponding data segment
UnableToMapPublishersDataSegment
};

} // namespace iox2

#endif
Loading

0 comments on commit 0c3b189

Please sign in to comment.