Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions tools/s2n-events/src/generate_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,37 @@ impl GenerateConfig {
OutputMode::Mut => quote!(),
}
}

pub fn c_ffi(
&self,
inner: &TokenStream,
connection_meta_c_type: &TokenStream,
connection_info_c_type: &TokenStream,
) -> TokenStream {
if !self.c_api {
return quote!();
}

assert!(
!connection_meta_c_type.is_empty(),
"An associated C type must be specified for ConnectionMeta with the #[c_type()] \
attribute."
);
assert!(
!connection_info_c_type.is_empty(),
"An associated C type must be specified for ConnectionInfo with the #[c_type()] \
attribute."
);

quote!(
pub mod c_ffi {
#[allow(unused_imports)]
use std::ffi::*;

#inner
}
)
}
}

impl ToTokens for OutputMode {
Expand Down
11 changes: 11 additions & 0 deletions tools/s2n-events/src/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ pub struct Output {
pub s2n_quic_core_path: TokenStream,
pub top_level: TokenStream,
pub feature_alloc: TokenStream,
pub c_ffi: TokenStream,
pub connection_meta_c_type: TokenStream,
pub connection_info_c_type: TokenStream,
pub root: PathBuf,
}

Expand Down Expand Up @@ -115,6 +118,9 @@ impl ToTokens for Output {
top_level,
feature_alloc: _,
crate_name,
c_ffi,
connection_meta_c_type,
connection_info_c_type,
root: _,
} = self;

Expand All @@ -129,6 +135,9 @@ impl ToTokens for Output {
let query_mut = self.config.query_mut();
let query_mut_tuple = self.config.query_mut_tuple();
let trait_constraints = self.config.trait_constraints();
let c_ffi = self
.config
.c_ffi(c_ffi, connection_meta_c_type, connection_info_c_type);

let ref_subscriber = self.config.ref_subscriber(quote!(
type ConnectionContext = T::ConnectionContext;
Expand Down Expand Up @@ -462,6 +471,8 @@ impl ToTokens for Output {
}
}

#c_ffi

#[cfg(any(test, feature = "testing"))]
pub mod testing {
use super::*;
Expand Down
95 changes: 90 additions & 5 deletions tools/s2n-events/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,34 @@ impl Struct {
}

fn to_tokens(&self, output: &mut Output) {
match self.attrs.c_definition {
true => self.to_tokens_c_definition(output),
false => self.to_tokens_rust_definition(output),
}
}

fn to_tokens_c_definition(&self, output: &mut Output) {
assert!(
self.attrs.event_name.is_none(),
"C struct definitions cannot be directly used as events."
);

let ident = &self.ident;
let extra_attrs = &self.attrs.extra;
let c_definition_attrs = &self.attrs.c_definition_attrs;
let builder_fields = self.fields.iter().map(Field::builder);

output.c_ffi.extend(quote!(
#c_definition_attrs
#[derive(Clone, Debug)]
#extra_attrs
pub struct #ident {
#(#builder_fields)*
}
));
}

fn to_tokens_rust_definition(&self, output: &mut Output) {
let Self {
attrs,
ident,
Expand Down Expand Up @@ -173,6 +201,12 @@ impl Struct {
}
));

if ident_str == "ConnectionMeta" {
output.connection_meta_c_type = attrs.associated_c_type.clone();
} else if ident_str == "ConnectionInfo" {
output.connection_info_c_type = attrs.associated_c_type.clone();
}

if let Some(event_name) = attrs.event_name.as_ref() {
output.api.extend(quote!(
#allow_deprecated
Expand Down Expand Up @@ -296,6 +330,12 @@ impl Struct {
self.output #lock.push(out);
}
));

assert!(
attrs.associated_c_type.is_empty(),
"C types cannot be associated with endpoint events. Publishing endpoint \
events from the C API is not yet supported."
);
}
Subject::Connection => {
output.subscriber.extend(quote!(
Expand Down Expand Up @@ -405,6 +445,15 @@ impl Struct {
}
}
));

if output.config.c_api {
let c_type = &attrs.associated_c_type;
assert!(
!c_type.is_empty(),
"Events must specify an associated C type with the #[c_type()] \
attribute.",
);
}
}
}
}
Expand Down Expand Up @@ -432,18 +481,41 @@ impl Enum {
}

fn to_tokens(&self, output: &mut Output) {
assert!(
self.attrs.event_name.is_none(),
"enum events are not currently supported"
);

match self.attrs.c_definition {
true => self.to_tokens_c_definition(output),
false => self.to_tokens_rust_definition(output),
}
}

fn to_tokens_c_definition(&self, output: &mut Output) {
let ident = &self.ident;
let extra_attrs = &self.attrs.extra;
let c_definition_attrs = &self.attrs.c_definition_attrs;
let builder_fields = self.variants.iter().map(Variant::builder);

output.c_ffi.extend(quote!(
#c_definition_attrs
#[derive(Clone, Debug)]
#extra_attrs
pub enum #ident {
#(#builder_fields)*
}
));
}

fn to_tokens_rust_definition(&self, output: &mut Output) {
let Self {
attrs,
ident,
generics,
variants,
} = self;

assert!(
attrs.event_name.is_none(),
"enum events are not currently supported"
);

let derive_attrs = &attrs.derive_attrs;
let builder_derive_attrs = &attrs.builder_derive_attrs;
let extra_attrs = &attrs.extra;
Expand Down Expand Up @@ -543,6 +615,9 @@ pub struct ContainerAttrs {
pub checkpoint: Vec<Checkpoint>,
pub measure_counter: Vec<Metric>,
pub extra: TokenStream,
pub associated_c_type: TokenStream,
pub c_definition: bool,
pub c_definition_attrs: TokenStream,
}

impl ContainerAttrs {
Expand All @@ -563,6 +638,9 @@ impl ContainerAttrs {
checkpoint: vec![],
measure_counter: vec![],
extra: quote!(),
associated_c_type: quote!(),
c_definition: false,
c_definition_attrs: TokenStream::default(),
};

for attr in attrs {
Expand Down Expand Up @@ -591,6 +669,13 @@ impl ContainerAttrs {
v.checkpoint.push(attr.parse_args().unwrap());
} else if path.is_ident("measure_counter") {
v.measure_counter.push(attr.parse_args().unwrap());
} else if path.is_ident("c_type") {
v.associated_c_type = attr.parse_args().unwrap();
} else if path.is_ident("repr") {
// Structs/enums with the #[repr(...)] attribute are assumed to be defined for the
// C API.
v.c_definition = true;
attr.to_tokens(&mut v.c_definition_attrs);
} else {
attr.to_tokens(&mut v.extra)
}
Expand Down
72 changes: 71 additions & 1 deletion tools/s2n-events/tests/c_ffi_events/event/generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,42 @@ pub mod api {
impl Event for CountEvent {
const NAME: &'static str = "count_event";
}
impl IntoEvent<builder::ConnectionMeta> for &c_ffi::s2n_event_connection_meta {
fn into_event(self) -> builder::ConnectionMeta {
let duration = Duration::from_nanos(self.timestamp);
let timestamp =
unsafe { s2n_quic_core::time::Timestamp::from_duration(duration).into_event() };
builder::ConnectionMeta { id: 0, timestamp }
}
}
impl IntoEvent<builder::ConnectionInfo> for &c_ffi::s2n_event_connection_info {
fn into_event(self) -> builder::ConnectionInfo {
builder::ConnectionInfo {}
}
}
impl<'a> IntoEvent<builder::ByteArrayEvent<'a>> for &c_ffi::s2n_byte_array_event {
fn into_event(self) -> builder::ByteArrayEvent<'a> {
let data =
unsafe { std::slice::from_raw_parts(self.data, self.len.try_into().unwrap()) };
builder::ByteArrayEvent { data }
}
}
impl IntoEvent<builder::TestEnum> for c_ffi::s2n_test_enum {
fn into_event(self) -> builder::TestEnum {
match self {
Self::S2N_TEST_VALUE_1 => builder::TestEnum::TestValue1,
Self::S2N_TEST_VALUE_2 => builder::TestEnum::TestValue2,
}
}
}
impl IntoEvent<builder::EnumEvent> for &c_ffi::s2n_enum_event {
fn into_event(self) -> builder::EnumEvent {
let value = self.value.clone();
builder::EnumEvent {
value: value.into_event(),
}
}
}
}
pub mod tracing {
#![doc = r" This module contains event integration with [`tracing`](https://docs.rs/tracing)"]
Expand Down Expand Up @@ -293,7 +329,7 @@ pub mod builder {
}
}
}
#[derive(Clone, Debug)]
#[derive(PartialEq, Clone, Debug)]
pub enum TestEnum {
TestValue1,
TestValue2,
Expand Down Expand Up @@ -638,6 +674,40 @@ mod traits {
}
}
}
pub mod c_ffi {
#[allow(unused_imports)]
use std::ffi::*;
#[repr(C)]
#[derive(Clone, Debug)]
#[allow(non_camel_case_types)]
pub struct s2n_event_connection_meta {
pub timestamp: u64,
}
#[repr(C)]
#[derive(Clone, Debug)]
#[allow(non_camel_case_types)]
pub struct s2n_event_connection_info {}
#[repr(C)]
#[derive(Clone, Debug)]
#[allow(non_camel_case_types)]
pub struct s2n_byte_array_event {
pub data: *const u8,
pub len: u32,
}
#[repr(C)]
#[derive(Clone, Debug)]
#[allow(non_camel_case_types)]
pub struct s2n_enum_event {
pub value: s2n_test_enum,
}
#[repr(C)]
#[derive(Clone, Debug)]
#[allow(non_camel_case_types)]
pub enum s2n_test_enum {
S2N_TEST_VALUE_1,
S2N_TEST_VALUE_2,
}
}
#[cfg(any(test, feature = "testing"))]
pub mod testing {
use super::*;
Expand Down
31 changes: 31 additions & 0 deletions tools/s2n-events/tests/c_ffi_events/events/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,42 @@ enum Subject {
},
}

#[c_type(s2n_event_connection_meta)]
struct ConnectionMeta {
id: u64,
timestamp: Timestamp,
}

#[repr(C)]
#[allow(non_camel_case_types)]
struct s2n_event_connection_meta {
timestamp: u64,
}

impl IntoEvent<builder::ConnectionMeta> for &c_ffi::s2n_event_connection_meta {
fn into_event(self) -> builder::ConnectionMeta {
let duration = Duration::from_nanos(self.timestamp);
let timestamp = unsafe {
s2n_quic_core::time::Timestamp::from_duration(duration).into_event()
};
builder::ConnectionMeta {
id: 0,
timestamp,
}
}
}

struct EndpointMeta {}

#[c_type(s2n_event_connection_info)]
struct ConnectionInfo {}

#[repr(C)]
#[allow(non_camel_case_types)]
struct s2n_event_connection_info {}

impl IntoEvent<builder::ConnectionInfo> for &c_ffi::s2n_event_connection_info {
fn into_event(self) -> builder::ConnectionInfo {
builder::ConnectionInfo {}
}
}
Loading
Loading