diff --git a/crates/wip-interface-macros/src/lib.rs b/crates/wip-interface-macros/src/lib.rs index a60e0c0..8615dac 100644 --- a/crates/wip-interface-macros/src/lib.rs +++ b/crates/wip-interface-macros/src/lib.rs @@ -112,6 +112,36 @@ fn expand_interface(attribute: TokenStream2, item: ItemTrait) -> syn::Result(); + operation.arguments_ident = format_ident!( + "{}{}ArgumentsN{}", + trait_ident, + pascal_case(&operation.name), + suffix, + span = operation.ident.span() + ); + } + } + let argument_items = operations.iter().map(argument_item); let operation_declarations = operations.iter().map(operation_declaration); let declaration_collectors = operations.iter().flat_map(operation_collectors); diff --git a/crates/wip-interface/tests/codecs.rs b/crates/wip-interface/tests/codecs.rs index a75c1cb..b8dc088 100644 --- a/crates/wip-interface/tests/codecs.rs +++ b/crates/wip-interface/tests/codecs.rs @@ -67,6 +67,17 @@ fn supported_values_round_trip() { assert!(fields.iter().all(|field| field.name != "priority")); assert_eq!(Request::decode(encoded).unwrap(), request); + let number = 42.5_f64; + assert_eq!(f64::type_expr(), TypeExpr::Number); + assert_eq!(f64::decode(number.encode().unwrap()).unwrap(), number); + + let narrow_number = 1.5_f32; + assert_eq!(f32::type_expr(), TypeExpr::Number); + assert_eq!( + f32::decode(narrow_number.encode().unwrap()).unwrap(), + narrow_number + ); + for color in [Color::Red, Color::Blue] { let encoded = color.clone().encode().unwrap(); let decoded = Color::decode(encoded).unwrap(); diff --git a/crates/wip-interface/tests/interface.rs b/crates/wip-interface/tests/interface.rs index 0ac94da..6779550 100644 --- a/crates/wip-interface/tests/interface.rs +++ b/crates/wip-interface/tests/interface.rs @@ -216,3 +216,41 @@ fn typed_dispatch_validates_decodes_invokes_encodes_and_validates() { let unknown = CatalogDefinition::dispatch(&AcceptingCatalog, "missing", vec![]).unwrap_err(); assert!(matches!(unknown, DispatchError::UnknownOperation(name) if name == "missing")); } + +/// Operations whose distinct source names normalize to the same PascalCase. +#[interface] +pub trait DistinctOperations { + /// Returns the first item marker. + fn item(&self) -> OperationResult; + + /// Returns the underscored item marker. + fn item_(&self) -> OperationResult; +} + +struct DistinctImplementation; + +impl DistinctOperations for DistinctImplementation { + fn item(&self) -> OperationResult { + Ok("item".into()) + } + + fn item_(&self) -> OperationResult { + Ok("item_".into()) + } +} + +#[test] +fn distinct_operation_names_always_generate_distinct_public_items() { + let descriptor = DistinctOperationsDefinition::descriptor(); + assert_eq!(descriptor.operations[0].name, "item"); + assert_eq!(descriptor.operations[1].name, "item_"); + + let first = DistinctOperationsDefinition::dispatch(&DistinctImplementation, "item", vec![]) + .unwrap() + .unwrap(); + let second = DistinctOperationsDefinition::dispatch(&DistinctImplementation, "item_", vec![]) + .unwrap() + .unwrap(); + assert_eq!(first, Value::String("item".into())); + assert_eq!(second, Value::String("item_".into())); +}