From ad9832d0857841fbc729af90a3819a85217e9a67 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Fri, 4 Apr 2025 12:48:51 +0300 Subject: [PATCH 1/4] Allow leaving out the message enum name. In this case we only generate the Channels impls for each case that has an attribute --- irpc-derive/src/lib.rs | 99 ++++++++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 42 deletions(-) diff --git a/irpc-derive/src/lib.rs b/irpc-derive/src/lib.rs index 636a5cb..ae84e66 100644 --- a/irpc-derive/src/lib.rs +++ b/irpc-derive/src/lib.rs @@ -48,6 +48,7 @@ fn generate_channels_impl( args.check_empty(attr_span)?; Ok(res) } + fn generate_from_impls( message_enum_name: &Ident, variants: &[(Ident, Type)], @@ -81,10 +82,10 @@ fn generate_from_impls( #[proc_macro_attribute] pub fn rpc_requests(attr: TokenStream, item: TokenStream) -> TokenStream { let mut input = parse_macro_input!(item as DeriveInput); - let MacroArgs { - service_name, - message_enum_name, - } = parse_macro_input!(attr as MacroArgs); + let args = parse_macro_input!(attr as MacroArgs); + + let service_name = args.service_name; + let message_enum_name = args.message_enum_name; let input_span = input.span(); let data_enum = match &mut input.data { @@ -155,66 +156,80 @@ pub fn rpc_requests(attr: TokenStream, item: TokenStream) -> TokenStream { } } - let message_variants = variants - .iter() - .map(|(variant_name, inner_type)| { - quote! { - #variant_name(::irpc::WithChannels<#inner_type, #service_name>) - } - }) - .collect::>(); + // Only generate the extended enum and related code if message_enum_name is provided + let extended_enum_code = if let Some(message_enum_name) = message_enum_name { + let message_variants = variants + .iter() + .map(|(variant_name, inner_type)| { + quote! { + #variant_name(::irpc::WithChannels<#inner_type, #service_name>) + } + }) + .collect::>(); - // Extract variant names for the match pattern - let variant_names = variants.iter().map(|(name, _)| name).collect::>(); + // Extract variant names for the match pattern + let variant_names = variants.iter().map(|(name, _)| name).collect::>(); - let message_enum = quote! { - #[derive(Debug)] - pub enum #message_enum_name { - #(#message_variants),* - } + let message_enum = quote! { + #[derive(Debug)] + pub enum #message_enum_name { + #(#message_variants),* + } - impl #message_enum_name { - /// Get the parent span of the message - pub fn parent_span(&self) -> tracing::Span { - let span = match self { - #(#message_enum_name::#variant_names(inner) => inner.parent_span_opt()),* - }; - span.cloned().unwrap_or_else(|| ::tracing::Span::current()) + impl #message_enum_name { + /// Get the parent span of the message + pub fn parent_span(&self) -> tracing::Span { + let span = match self { + #(#message_enum_name::#variant_names(inner) => inner.parent_span_opt()),* + }; + span.cloned().unwrap_or_else(|| ::tracing::Span::current()) + } } - } - }; + }; - // Generate the From implementations - generate_from_impls( - &message_enum_name, - &variants, - &service_name, - &input.ident, - &mut additional_items, - ); + // Generate the From implementations + generate_from_impls( + &message_enum_name, + &variants, + &service_name, + &input.ident, + &mut additional_items, + ); + + message_enum + } else { + // If no message_enum_name is provided, don't generate the extended enum + quote! {} + }; let output = quote! { #input - #message_enum - #(#additional_items)* + + #extended_enum_code }; output.into() } -// Parse arguments in the format (ServiceType, MessageEnumName) +// Parse arguments in the format (ServiceType) or (ServiceType, MessageEnumName) struct MacroArgs { service_name: Ident, - message_enum_name: Ident, + message_enum_name: Option, } impl Parse for MacroArgs { fn parse(input: ParseStream) -> syn::Result { let service_name: Ident = input.parse()?; - let _: Token![,] = input.parse()?; - let message_enum_name: Ident = input.parse()?; + + // Check if there's a comma, indicating a second argument + let message_enum_name = if input.peek(Token![,]) { + let _: Token![,] = input.parse()?; + Some(input.parse()?) + } else { + None + }; Ok(MacroArgs { service_name, From e0060efc28c990cfaaff129485a58c03b6e031d5 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Fri, 4 Apr 2025 12:55:45 +0300 Subject: [PATCH 2/4] Add new message_enum macro. --- irpc-derive/src/lib.rs | 152 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 140 insertions(+), 12 deletions(-) diff --git a/irpc-derive/src/lib.rs b/irpc-derive/src/lib.rs index ae84e66..da8e01d 100644 --- a/irpc-derive/src/lib.rs +++ b/irpc-derive/src/lib.rs @@ -24,6 +24,21 @@ const RX_ATTR: &str = "rx"; /// Fully qualified path to the default rx type const DEFAULT_RX_TYPE: &str = "::irpc::channel::none::NoReceiver"; +/// Generate parent span method for an enum +fn generate_parent_span_impl(enum_name: &Ident, variant_names: &[&Ident]) -> TokenStream2 { + quote! { + impl #enum_name { + /// Get the parent span of the message + pub fn parent_span(&self) -> tracing::Span { + let span = match self { + #(#enum_name::#variant_names(inner) => inner.parent_span_opt()),* + }; + span.cloned().unwrap_or_else(|| ::tracing::Span::current()) + } + } + } +} + fn generate_channels_impl( mut args: NamedTypeArgs, service_name: &Ident, @@ -79,6 +94,123 @@ fn generate_from_impls( } } +/// Transforms an enum into a message enum where each variant wraps its type in WithChannels +#[proc_macro_attribute] +pub fn message_enum(attr: TokenStream, item: TokenStream) -> TokenStream { + let service_name = parse_macro_input!(attr as Ident); + let mut input = parse_macro_input!(item as DeriveInput); + let enum_name = &input.ident; + + // Make sure we're dealing with an enum + let data_enum = match &mut input.data { + Data::Enum(data_enum) => data_enum, + _ => { + return syn::Error::new(input.span(), "message_enum can only be applied to enums") + .to_compile_error() + .into(); + } + }; + + // Transform each variant to use WithChannels + for variant in &mut data_enum.variants { + match &mut variant.fields { + Fields::Unnamed(fields) if fields.unnamed.len() == 1 => { + let inner_type = &fields.unnamed[0].ty; + let new_type = syn::parse_quote! { + ::irpc::WithChannels<#inner_type, #service_name> + }; + fields.unnamed[0].ty = new_type; + } + _ => { + return syn::Error::new( + variant.span(), + "Each variant must have exactly one unnamed field", + ) + .to_compile_error() + .into(); + } + } + } + + // Extract variant names for parent_span implementation + let variant_names: Vec<_> = data_enum + .variants + .iter() + .map(|variant| &variant.ident) + .collect(); + + // Generate parent_span method + let parent_span_impl = generate_parent_span_impl(enum_name, &variant_names); + + // Generate From implementations for each variant + let mut from_impls = TokenStream2::new(); + for variant in &data_enum.variants { + if let Fields::Unnamed(fields) = &variant.fields { + if fields.unnamed.len() == 1 { + let variant_name = &variant.ident; + let wrapped_type = &fields.unnamed[0].ty; + + // Extract the inner type from WithChannels + // We know the structure, so we can extract it this way + let inner_type = match wrapped_type { + Type::Path(type_path) => { + // Find the first generic argument which is our original type + if let Some(segment) = type_path.path.segments.last() { + if let syn::PathArguments::AngleBracketed(args) = &segment.arguments { + if let Some(generic_arg) = args.args.first() { + if let syn::GenericArgument::Type(inner) = generic_arg { + inner.clone() + } else { + continue; + } + } else { + continue; + } + } else { + continue; + } + } else { + continue; + } + } + _ => continue, + }; + + // Generate From for the enum + let from_inner = quote! { + impl From<#inner_type> for #enum_name { + fn from(value: #inner_type) -> Self { + #enum_name::#variant_name(value.into()) + } + } + }; + + // Generate From> for the enum + let from_wrapped = quote! { + impl From<#wrapped_type> for #enum_name { + fn from(value: #wrapped_type) -> Self { + #enum_name::#variant_name(value) + } + } + }; + + from_impls.extend(from_inner); + from_impls.extend(from_wrapped); + } + } + } + + let result = quote! { + #input + + #parent_span_impl + + #from_impls + }; + + result.into() +} + #[proc_macro_attribute] pub fn rpc_requests(attr: TokenStream, item: TokenStream) -> TokenStream { let mut input = parse_macro_input!(item as DeriveInput); @@ -168,25 +300,18 @@ pub fn rpc_requests(attr: TokenStream, item: TokenStream) -> TokenStream { .collect::>(); // Extract variant names for the match pattern - let variant_names = variants.iter().map(|(name, _)| name).collect::>(); + let variant_names: Vec<&Ident> = variants.iter().map(|(name, _)| name).collect(); let message_enum = quote! { #[derive(Debug)] pub enum #message_enum_name { #(#message_variants),* } - - impl #message_enum_name { - /// Get the parent span of the message - pub fn parent_span(&self) -> tracing::Span { - let span = match self { - #(#message_enum_name::#variant_names(inner) => inner.parent_span_opt()),* - }; - span.cloned().unwrap_or_else(|| ::tracing::Span::current()) - } - } }; + // Generate parent_span method + let parent_span_impl = generate_parent_span_impl(&message_enum_name, &variant_names); + // Generate the From implementations generate_from_impls( &message_enum_name, @@ -196,7 +321,10 @@ pub fn rpc_requests(attr: TokenStream, item: TokenStream) -> TokenStream { &mut additional_items, ); - message_enum + quote! { + #message_enum + #parent_span_impl + } } else { // If no message_enum_name is provided, don't generate the extended enum quote! {} From 83585fe8fd5d6046dc8d0c821ed724e7ebb41470 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Fri, 4 Apr 2025 15:08:02 +0300 Subject: [PATCH 3/4] Change the macro so that the message enum generation is optional Also add the ability to define type aliases for each case --- examples/compute.rs | 2 +- examples/derive.rs | 2 +- irpc-derive/src/lib.rs | 348 +++++++++++++++++++---------------- irpc-iroh/examples/derive.rs | 2 +- tests/derive.rs | 2 +- 5 files changed, 197 insertions(+), 159 deletions(-) diff --git a/examples/compute.rs b/examples/compute.rs index ba38cd0..c52dad4 100644 --- a/examples/compute.rs +++ b/examples/compute.rs @@ -56,7 +56,7 @@ enum ComputeRequest { } // Define the protocol and message enums using the macro -#[rpc_requests(ComputeService, ComputeMessage)] +#[rpc_requests(ComputeService, message = ComputeMessage)] #[derive(Serialize, Deserialize)] enum ComputeProtocol { #[rpc(tx=oneshot::Sender)] diff --git a/examples/derive.rs b/examples/derive.rs index 2e60e3e..c244834 100644 --- a/examples/derive.rs +++ b/examples/derive.rs @@ -39,7 +39,7 @@ struct Set { // Use the macro to generate both the StorageProtocol and StorageMessage enums // plus implement Channels for each type -#[rpc_requests(StorageService, StorageMessage)] +#[rpc_requests(StorageService, message = StorageMessage)] #[derive(Serialize, Deserialize)] enum StorageProtocol { #[rpc(tx=oneshot::Sender>)] diff --git a/irpc-derive/src/lib.rs b/irpc-derive/src/lib.rs index da8e01d..08264b5 100644 --- a/irpc-derive/src/lib.rs +++ b/irpc-derive/src/lib.rs @@ -7,7 +7,7 @@ use syn::{ parse::{Parse, ParseStream}, parse_macro_input, spanned::Spanned, - Data, DeriveInput, Fields, Ident, Token, Type, + Data, DeriveInput, Fields, Ident, LitStr, Token, Type, }; // Helper function for error reporting @@ -64,153 +64,141 @@ fn generate_channels_impl( Ok(res) } -fn generate_from_impls( - message_enum_name: &Ident, - variants: &[(Ident, Type)], - service_name: &Ident, - original_enum_name: &Ident, - additional_items: &mut Vec, -) { - // Generate and add From impls for the message enum - for (variant_name, inner_type) in variants { - let message_impl = quote! { - impl From<::irpc::WithChannels<#inner_type, #service_name>> for #message_enum_name { - fn from(value: ::irpc::WithChannels<#inner_type, #service_name>) -> Self { - #message_enum_name::#variant_name(value) +/// Generates From implementations for cases with rpc attributes +fn generate_case_from_impls( + enum_name: &Ident, + variants_with_attr: &[(Ident, Type)], +) -> TokenStream2 { + let mut impls = quote! {}; + + // Generate From implementations for each case that has an rpc attribute + for (variant_name, inner_type) in variants_with_attr { + let impl_tokens = quote! { + impl From<#inner_type> for #enum_name { + fn from(value: #inner_type) -> Self { + #enum_name::#variant_name(value) } } }; - additional_items.extend(message_impl); - // Generate and add From impls for the original enum - let original_impl = quote! { - impl From<#inner_type> for #original_enum_name { - fn from(value: #inner_type) -> Self { - #original_enum_name::#variant_name(value) - } - } + impls = quote! { + #impls + #impl_tokens }; - additional_items.extend(original_impl); } -} -/// Transforms an enum into a message enum where each variant wraps its type in WithChannels -#[proc_macro_attribute] -pub fn message_enum(attr: TokenStream, item: TokenStream) -> TokenStream { - let service_name = parse_macro_input!(attr as Ident); - let mut input = parse_macro_input!(item as DeriveInput); - let enum_name = &input.ident; + impls +} - // Make sure we're dealing with an enum - let data_enum = match &mut input.data { - Data::Enum(data_enum) => data_enum, - _ => { - return syn::Error::new(input.span(), "message_enum can only be applied to enums") - .to_compile_error() - .into(); - } - }; +/// Generate From implementations for message enum variants +fn generate_message_enum_from_impls( + message_enum_name: &Ident, + variants_with_attr: &[(Ident, Type)], + service_name: &Ident, +) -> TokenStream2 { + let mut impls = quote! {}; - // Transform each variant to use WithChannels - for variant in &mut data_enum.variants { - match &mut variant.fields { - Fields::Unnamed(fields) if fields.unnamed.len() == 1 => { - let inner_type = &fields.unnamed[0].ty; - let new_type = syn::parse_quote! { - ::irpc::WithChannels<#inner_type, #service_name> - }; - fields.unnamed[0].ty = new_type; - } - _ => { - return syn::Error::new( - variant.span(), - "Each variant must have exactly one unnamed field", - ) - .to_compile_error() - .into(); + // Generate From> implementations for each case with an rpc attribute + for (variant_name, inner_type) in variants_with_attr { + let impl_tokens = quote! { + impl From<::irpc::WithChannels<#inner_type, #service_name>> for #message_enum_name { + fn from(value: ::irpc::WithChannels<#inner_type, #service_name>) -> Self { + #message_enum_name::#variant_name(value) + } } - } + }; + + impls = quote! { + #impls + #impl_tokens + }; } - // Extract variant names for parent_span implementation - let variant_names: Vec<_> = data_enum - .variants - .iter() - .map(|variant| &variant.ident) - .collect(); - - // Generate parent_span method - let parent_span_impl = generate_parent_span_impl(enum_name, &variant_names); - - // Generate From implementations for each variant - let mut from_impls = TokenStream2::new(); - for variant in &data_enum.variants { - if let Fields::Unnamed(fields) = &variant.fields { - if fields.unnamed.len() == 1 { - let variant_name = &variant.ident; - let wrapped_type = &fields.unnamed[0].ty; - - // Extract the inner type from WithChannels - // We know the structure, so we can extract it this way - let inner_type = match wrapped_type { - Type::Path(type_path) => { - // Find the first generic argument which is our original type - if let Some(segment) = type_path.path.segments.last() { - if let syn::PathArguments::AngleBracketed(args) = &segment.arguments { - if let Some(generic_arg) = args.args.first() { - if let syn::GenericArgument::Type(inner) = generic_arg { - inner.clone() - } else { - continue; - } - } else { - continue; - } - } else { - continue; - } - } else { - continue; - } - } - _ => continue, - }; + impls +} - // Generate From for the enum - let from_inner = quote! { - impl From<#inner_type> for #enum_name { - fn from(value: #inner_type) -> Self { - #enum_name::#variant_name(value.into()) - } - } - }; +/// Generate type aliases for WithChannels +fn generate_type_aliases( + variants: &[(Ident, Type)], + service_name: &Ident, + suffix: &str, +) -> TokenStream2 { + let mut aliases = quote! {}; - // Generate From> for the enum - let from_wrapped = quote! { - impl From<#wrapped_type> for #enum_name { - fn from(value: #wrapped_type) -> Self { - #enum_name::#variant_name(value) - } - } - }; + for (variant_name, inner_type) in variants { + // Create a type name using the variant name + suffix + // For example: Sum + "Msg" = SumMsg + let type_name = format!("{}{}", variant_name, suffix); + let type_ident = Ident::new(&type_name, variant_name.span()); + + let alias = quote! { + /// Type alias for WithChannels<#inner_type, #service_name> + pub type #type_ident = ::irpc::WithChannels<#inner_type, #service_name>; + }; - from_impls.extend(from_inner); - from_impls.extend(from_wrapped); - } - } + aliases = quote! { + #aliases + #alias + }; } - let result = quote! { - #input - - #parent_span_impl - - #from_impls - }; - - result.into() + aliases } +/// Processes an RPC request enum and generates channel implementations. +/// +/// This macro takes a protocol enum where each variant represents a different RPC request type +/// and generates the necessary channel implementations for each request. +/// +/// # Macro Arguments +/// +/// * First positional argument (required): The service type that will handle these requests +/// * `message` (optional): Generate an extended enum wrapping each type in `WithChannels` +/// * `alias` (optional): Generate type aliases with the given suffix for each `WithChannels` +/// +/// # Variant Attributes +/// +/// Individual enum variants can be annotated with the `#[rpc(...)]` attribute to specify channel types: +/// +/// * `#[rpc(tx=SomeType)]`: Specify the transmitter/sender channel type (required) +/// * `#[rpc(tx=SomeType, rx=OtherType)]`: Also specify a receiver channel type (optional) +/// +/// If `rx` is not specified, it defaults to `NoReceiver`. +/// +/// # Examples +/// +/// Basic usage: +/// ``` +/// #[rpc_requests(ComputeService)] +/// enum ComputeProtocol { +/// #[rpc(tx=oneshot::Sender)] +/// Sqr(Sqr), +/// #[rpc(tx=oneshot::Sender)] +/// Sum(Sum), +/// } +/// ``` +/// +/// With a message enum: +/// ``` +/// #[rpc_requests(ComputeService, message = ComputeMessage)] +/// enum ComputeProtocol { +/// #[rpc(tx=oneshot::Sender)] +/// Sqr(Sqr), +/// #[rpc(tx=oneshot::Sender)] +/// Sum(Sum), +/// } +/// ``` +/// +/// With type aliases: +/// ``` +/// #[rpc_requests(ComputeService, alias = "Msg")] +/// enum ComputeProtocol { +/// #[rpc(tx=oneshot::Sender)] +/// Sqr(Sqr), // Generates type SqrMsg = WithChannels +/// #[rpc(tx=oneshot::Sender)] +/// Sum(Sum), // Generates type SumMsg = WithChannels +/// } +/// ``` #[proc_macro_attribute] pub fn rpc_requests(attr: TokenStream, item: TokenStream) -> TokenStream { let mut input = parse_macro_input!(item as DeriveInput); @@ -218,19 +206,24 @@ pub fn rpc_requests(attr: TokenStream, item: TokenStream) -> TokenStream { let service_name = args.service_name; let message_enum_name = args.message_enum_name; + let alias_suffix = args.alias_suffix; + let enum_name = &input.ident; let input_span = input.span(); + let data_enum = match &mut input.data { Data::Enum(data_enum) => data_enum, _ => return error_tokens(input.span(), "RpcRequests can only be applied to enums"), }; - // builder for the trait impls - let mut additional_items = Vec::new(); - // types to check for uniqueness + // Collect trait implementations + let mut channel_impls = Vec::new(); + // Types to check for uniqueness let mut types = HashSet::new(); - // variant names and types - let mut variants = Vec::new(); + // All variant names and types + let mut all_variants = Vec::new(); + // Variants with rpc attributes (for From implementations) + let mut variants_with_attr = Vec::new(); for variant in &mut data_enum.variants { // Check field structure for every variant @@ -243,11 +236,12 @@ pub fn rpc_requests(attr: TokenStream, item: TokenStream) -> TokenStream { ) } }; - variants.push((variant.ident.clone(), request_type.clone())); + all_variants.push((variant.ident.clone(), request_type.clone())); if !types.insert(request_type.to_token_stream().to_string()) { return error_tokens(input_span, "Each variant must have a unique request type"); } + // Find and remove the rpc attribute let mut rpc_attr = None; let mut multiple_rpc_attrs = false; @@ -274,23 +268,36 @@ pub fn rpc_requests(attr: TokenStream, item: TokenStream) -> TokenStream { ); } - // if there is no attr, the user has to impl Channels manually + // Process variants with rpc attributes if let Some(attr) = rpc_attr { + variants_with_attr.push((variant.ident.clone(), request_type.clone())); + let args = match attr.parse_args::() { Ok(info) => info, Err(e) => return e.to_compile_error().into(), }; match generate_channels_impl(args, &service_name, request_type, attr.span()) { - Ok(impls) => additional_items.extend(impls), + Ok(impls) => channel_impls.push(impls), Err(e) => return e.to_compile_error().into(), } } } - // Only generate the extended enum and related code if message_enum_name is provided + // Generate From implementations for the original enum (only for variants with rpc attributes) + let original_from_impls = generate_case_from_impls(enum_name, &variants_with_attr); + + // Generate type aliases if requested + let type_aliases = if let Some(suffix) = alias_suffix { + // Use all variants for type aliases, not just those with rpc attributes + generate_type_aliases(&all_variants, &service_name, &suffix) + } else { + quote! {} + }; + + // Generate the extended message enum if requested let extended_enum_code = if let Some(message_enum_name) = message_enum_name { - let message_variants = variants + let message_variants = all_variants .iter() .map(|(variant_name, inner_type)| { quote! { @@ -299,9 +306,10 @@ pub fn rpc_requests(attr: TokenStream, item: TokenStream) -> TokenStream { }) .collect::>(); - // Extract variant names for the match pattern - let variant_names: Vec<&Ident> = variants.iter().map(|(name, _)| name).collect(); + // Extract variant names for the parent_span implementation + let variant_names: Vec<&Ident> = all_variants.iter().map(|(name, _)| name).collect(); + // Create the message enum definition let message_enum = quote! { #[derive(Debug)] pub enum #message_enum_name { @@ -312,56 +320,86 @@ pub fn rpc_requests(attr: TokenStream, item: TokenStream) -> TokenStream { // Generate parent_span method let parent_span_impl = generate_parent_span_impl(&message_enum_name, &variant_names); - // Generate the From implementations - generate_from_impls( + // Generate From implementations for the message enum (only for variants with rpc attributes) + let message_from_impls = generate_message_enum_from_impls( &message_enum_name, - &variants, + &variants_with_attr, &service_name, - &input.ident, - &mut additional_items, ); quote! { #message_enum #parent_span_impl + #message_from_impls } } else { // If no message_enum_name is provided, don't generate the extended enum quote! {} }; + // Combine everything let output = quote! { #input - #(#additional_items)* + // Channel implementations + #(#channel_impls)* + + // From implementations for the original enum + #original_from_impls + // Type aliases for WithChannels + #type_aliases + + // Extended enum and its implementations #extended_enum_code }; output.into() } -// Parse arguments in the format (ServiceType) or (ServiceType, MessageEnumName) +// Parse arguments for the macro struct MacroArgs { service_name: Ident, message_enum_name: Option, + alias_suffix: Option, } impl Parse for MacroArgs { fn parse(input: ParseStream) -> syn::Result { + // First argument must be the service name (positional) let service_name: Ident = input.parse()?; - // Check if there's a comma, indicating a second argument - let message_enum_name = if input.peek(Token![,]) { - let _: Token![,] = input.parse()?; - Some(input.parse()?) - } else { - None - }; + // Initialize optional parameters + let mut message_enum_name = None; + let mut alias_suffix = None; + + // Parse any additional named parameters + while input.peek(Token![,]) { + input.parse::()?; + let param_name: Ident = input.parse()?; + input.parse::()?; + + match param_name.to_string().as_str() { + "message" => { + message_enum_name = Some(input.parse()?); + } + "alias" => { + let lit: LitStr = input.parse()?; + alias_suffix = Some(lit.value()); + } + _ => { + return Err(syn::Error::new( + param_name.span(), + format!("Unknown parameter: {}", param_name), + )); + } + } + } Ok(MacroArgs { service_name, message_enum_name, + alias_suffix, }) } } diff --git a/irpc-iroh/examples/derive.rs b/irpc-iroh/examples/derive.rs index 54ccbed..faa30f1 100644 --- a/irpc-iroh/examples/derive.rs +++ b/irpc-iroh/examples/derive.rs @@ -35,7 +35,7 @@ struct Set { // Use the macro to generate both the StorageProtocol and StorageMessage enums // plus implement Channels for each type -#[rpc_requests(StorageService, StorageMessage)] +#[rpc_requests(StorageService, message = StorageMessage)] #[derive(Serialize, Deserialize)] enum StorageProtocol { #[rpc(tx=oneshot::Sender>)] diff --git a/tests/derive.rs b/tests/derive.rs index 9b756b5..0d622d6 100644 --- a/tests/derive.rs +++ b/tests/derive.rs @@ -34,7 +34,7 @@ fn derive_simple() { #[derive(Debug, Serialize, Deserialize)] struct Response4; - #[rpc_requests(Service, RequestWithChannels)] + #[rpc_requests(Service, message = RequestWithChannels)] #[derive(Debug, Serialize, Deserialize)] enum Request { #[rpc(tx=oneshot::Sender<()>)] From a3f1c95c0c365675faec9ba4f966bbed3a83c5d4 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Fri, 4 Apr 2025 15:35:57 +0300 Subject: [PATCH 4/4] Move deps to workspace No more versioned deps in child Cargo.toml --- Cargo.lock | 39 --------------------------------------- Cargo.toml | 29 ++++++++++++++++++++--------- irpc-iroh/Cargo.toml | 16 ++++++++-------- 3 files changed, 28 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f485c4b..df39984 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -125,15 +125,6 @@ dependencies = [ "syn 2.0.100", ] -[[package]] -name = "atomic-polyfill" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" -dependencies = [ - "critical-section", -] - [[package]] name = "atomic-waker" version = "1.1.2" @@ -399,12 +390,6 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" -[[package]] -name = "critical-section" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" - [[package]] name = "crossbeam-channel" version = "0.5.14" @@ -1012,15 +997,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "hash32" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", -] - [[package]] name = "hashbrown" version = "0.14.5" @@ -1038,20 +1014,6 @@ dependencies = [ "foldhash", ] -[[package]] -name = "heapless" -version = "0.7.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" -dependencies = [ - "atomic-polyfill", - "hash32", - "rustc_version", - "serde", - "spin", - "stable_deref_trait", -] - [[package]] name = "heck" version = "0.5.0" @@ -2521,7 +2483,6 @@ dependencies = [ "cobs", "embedded-io 0.4.0", "embedded-io 0.6.1", - "heapless", "postcard-derive", "serde", ] diff --git a/Cargo.toml b/Cargo.toml index 5ed8986..661c7ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,18 +14,18 @@ rust-version = "1.76" [dependencies] # we require serde even in non-rpc mode -serde = { version = "1", default-features = false } +serde = { workspace = true } # just for the oneshot and mpsc queues -tokio = { version = "1.44", features = ["sync"], default-features = false } +tokio = { workspace = true, features = ["sync"] } # for PollSender (which for some reason is not available in the main tokio api) tokio-util = { version = "0.7.14", default-features = false } # errors thiserror = "2.0.12" # used in the endpoint handler code when using rpc -tracing = { version = "0.1.41", optional = true } +tracing = { workspace = true, optional = true } # used to ser/de messages when using rpc -postcard = { version = "1.1.1", features = ["alloc", "use-std"], optional = true } +postcard = { workspace = true, features = ["alloc", "use-std"], optional = true } # currently only transport when using rpc quinn = { version = "0.13.0", package = "iroh-quinn", optional = true } # used as a buffer for serialization when using rpc @@ -35,22 +35,23 @@ rustls = { version = "0.23.5", default-features = false, features = ["std"], opt # used in the test utils to generate quinn endpoints rcgen = { version = "0.13.2", optional = true } # used in the test utils to generate quinn endpoints -anyhow = { version = "1.0.66", optional = true } +anyhow = { workspace = true, optional = true } # used in the benches futures-buffered ={ version = "0.2.9", optional = true } [dev-dependencies] -tracing-subscriber = { version = "0.3.19", features = ["fmt"] } +tracing-subscriber = { workspace = true, features = ["fmt"] } # used in the derive example. This must not be a main crate dep or else it will be circular! irpc-derive = { version = "0.1.0", path = "./irpc-derive" } -# just convenient for the enum definitions +# just convenient for the enum definitions, in the manual example derive_more = { version = "2", features = ["from"] } # we need full for example main etc. -tokio = { version = "1", features = ["full"] } +tokio = { workspace = true, features = ["full"] } # formatting thousands = "0.2.0" # for AbortOnDropHandle -n0-future = { version = "0.1.2" } +n0-future = { workspace = true } +# macro tests trybuild = "1.0.104" [features] @@ -71,3 +72,13 @@ rustdoc-args = ["--cfg", "quicrpc_docsrs"] [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ["cfg(quicrpc_docsrs)"] } + +[workspace.dependencies] +anyhow = { version = "1.0.66" } +tokio = { version = "1.44", default-features = false } +postcard = { version = "1.1.1", default-features = false } +serde = { version = "1", default-features = false } +tracing = { version = "0.1.41", default-features = false } +n0-future = { version = "0.1.2", default-features = false } +tracing-subscriber = { version = "0.3.19", default-features = false } +iroh = { version = "0.34" } \ No newline at end of file diff --git a/irpc-iroh/Cargo.toml b/irpc-iroh/Cargo.toml index 3a0c920..afd722f 100644 --- a/irpc-iroh/Cargo.toml +++ b/irpc-iroh/Cargo.toml @@ -10,15 +10,15 @@ repository = "https://github.com/n0-computer/irpc" description = "Iroh transport for irpc" [dependencies] -anyhow = "1.0.97" -iroh = "0.34.0" +anyhow = { workspace = true } +iroh = { workspace = true } +tokio = { workspace = true, features = ["sync"] } +tracing = { workspace = true } +serde = { workspace = true } +postcard = { workspace = true, features = ["alloc", "use-std"] } irpc = { version = "0.1.0", path = ".." } -tokio = { version = "1.44.1", default-features = false, features = ["sync"] } -serde = { version = "1", default-features = false } -tracing = { version = "0.1.41" } -postcard = { version = "1.1.1", features = ["alloc", "use-std"] } [dev-dependencies] -n0-future = { version = "0.1.2", default-features = false } +n0-future = { workspace = true } +tracing-subscriber = { workspace = true, features = ["fmt"] } irpc-derive = { version = "0.1.0", path = "../irpc-derive" } -tracing-subscriber = { version = "0.3.19", features = ["fmt"] }