diff --git a/spec-trait-impl/crates/spec-trait-bin/src/examples/sself.rs b/spec-trait-impl/crates/spec-trait-bin/src/examples/sself.rs index d42b378..e1ad482 100644 --- a/spec-trait-impl/crates/spec-trait-bin/src/examples/sself.rs +++ b/spec-trait-impl/crates/spec-trait-bin/src/examples/sself.rs @@ -31,6 +31,12 @@ impl SelfTrait for (U, V) { } } +impl SelfTrait for i32 { + fn self_method(&self, _x: T) { + println!("i32: Default"); + } +} + #[when(T = u8)] impl SelfTrait for BaseType1 { fn self_method(&self, _x: T) { @@ -59,6 +65,13 @@ impl SelfTrait for (U, V) { } } +#[when(T = u8)] +impl SelfTrait for i32 { + fn self_method(&self, _x: T) { + println!("i32: T is u8"); + } +} + pub fn run() { println!("\n- Self Type Examples:"); @@ -70,13 +83,12 @@ pub fn run() { spec! { y.self_method(42u8); BaseType2; [u8] } // -> "BaseType2: T is u8" spec! { y.self_method(1i32); BaseType2; [i32] } // -> "BaseType2: Default" - let v1 = vec![1u8]; - let v2 = vec![1i32]; - spec! { v1.self_method(42u8); Vec; [u8] } // -> "Vec: T is u8" - spec! { v2.self_method(1i32); Vec; [i32] } // -> "Vec: Default" + spec! { vec![1u8].self_method(42u8); Vec; [u8] } // -> "Vec: T is u8" + spec! { vec![1i32].self_method(1i32); Vec; [i32] } // -> "Vec: Default" + + spec! { (1u8, 2u8).self_method(42u8); (u8, u8); [u8] } // -> "(U, V): T is u8" + spec! { (1i32, 2i32).self_method(1i32); (i32, i32); [i32] } // -> "(U, V): Default" - let t1 = (1u8, 2u8); - let t2 = (1i32, 2i32); - spec! { t1.self_method(42u8); (u8, u8); [u8] } // -> "(U, V): T is u8" - spec! { t2.self_method(1i32); (i32, i32); [i32] } // -> "(U, V): Default" + spec! { 1i32.abs().self_method(42u8); i32; [u8] } // -> "i32: T is u8" + spec! { 1i32.abs().self_method(1i32); i32; [i32] } // -> "i32: Default" } diff --git a/spec-trait-impl/crates/spec-trait-macro/src/annotations.rs b/spec-trait-impl/crates/spec-trait-macro/src/annotations.rs index b1c6e55..4510fc3 100644 --- a/spec-trait-impl/crates/spec-trait-macro/src/annotations.rs +++ b/spec-trait-impl/crates/spec-trait-macro/src/annotations.rs @@ -3,7 +3,7 @@ use spec_trait_utils::conversions::to_string; use spec_trait_utils::parsing::{ParseTypeOrLifetimeOrTrait, parse_type_or_lifetime_or_trait}; use std::fmt::Debug; use syn::parse::{Parse, ParseStream}; -use syn::{Error, Expr, Ident, Lit, Token, Type, bracketed, parenthesized, token}; +use syn::{Error, Expr, Token, Type, bracketed, token}; #[derive(Debug, PartialEq, Clone)] pub enum Annotation { @@ -87,28 +87,25 @@ impl Parse for AnnotationBody { /// - `x.my_method(1u8, "abc")` -> `("x", "my_method", ["1u8", "abc"])` /// - `var.foo()` -> `("var", "foo", [])` fn parse_call(input: ParseStream) -> Result<(String, String, Vec), Error> { - let var = if input.peek(Ident) { - to_string(&input.parse::()?) - } else if input.peek(Lit) { - to_string(&input.parse::()?) - } else { - return Err(Error::new(input.span(), "Expected identifier or literal")); + let method_call = match input.parse::()? { + Expr::MethodCall(mc) => mc, + _ => { + return Err(Error::new( + input.span(), + "Expected a method call of the form `variable.function(args...)`", + )); + } }; - input.parse::()?; // consume the '.' token - - let fn_: Ident = input.parse()?; - - let content; - parenthesized!(content in input); // consume the '(' and ')' token pair - - let args = content.parse_terminated(Expr::parse, Token![,])?; + let var = to_string(&method_call.receiver); + let fn_ = method_call.method.to_string(); + let args = method_call.args.iter().map(to_string).collect(); if input.peek(Token![;]) { input.parse::()?; // consume the ';' token } - Ok((var, fn_.to_string(), args.iter().map(to_string).collect())) + Ok((var, fn_, args)) } /// Parse the variable type and argument types @@ -229,6 +226,29 @@ mod tests { } } + #[test] + fn type_formats() { + let input = quote! { (a,b).foo(); (i32,i32) }; + let result = AnnotationBody::try_from(input).unwrap(); + + assert_eq!(result.var.replace(" ", ""), "(a,b)"); + assert_eq!(result.fn_, "foo"); + assert!(result.args.is_empty()); + assert_eq!(result.var_type.replace(" ", ""), "(i32,i32)"); + assert!(result.args_types.is_empty()); + assert!(result.annotations.is_empty()); + + let input = quote! { [1,2].foo(); [i32;2] }; + let result = AnnotationBody::try_from(input).unwrap(); + + assert_eq!(result.var.replace(" ", ""), "[1,2]"); + assert_eq!(result.fn_, "foo"); + assert!(result.args.is_empty()); + assert_eq!(result.var_type.replace(" ", ""), "[i32;2]"); + assert!(result.args_types.is_empty()); + assert!(result.annotations.is_empty()); + } + #[test] fn annotations() { let input = quote! {