Skip to content
Merged
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
28 changes: 20 additions & 8 deletions spec-trait-impl/crates/spec-trait-bin/src/examples/sself.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ impl<T, U, V> SelfTrait<T> for (U, V) {
}
}

impl<T> SelfTrait<T> for i32 {
fn self_method(&self, _x: T) {
println!("i32: Default");
}
}

#[when(T = u8)]
impl<T> SelfTrait<T> for BaseType1 {
fn self_method(&self, _x: T) {
Expand Down Expand Up @@ -59,6 +65,13 @@ impl<T, U, V> SelfTrait<T> for (U, V) {
}
}

#[when(T = u8)]
impl<T> SelfTrait<T> for i32 {
fn self_method(&self, _x: T) {
println!("i32: T is u8");
}
}

pub fn run() {
println!("\n- Self Type Examples:");

Expand All @@ -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>; [u8] } // -> "Vec<U>: T is u8"
spec! { v2.self_method(1i32); Vec<i32>; [i32] } // -> "Vec<U>: Default"
spec! { vec![1u8].self_method(42u8); Vec<u8>; [u8] } // -> "Vec<U>: T is u8"
spec! { vec![1i32].self_method(1i32); Vec<i32>; [i32] } // -> "Vec<U>: 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"
}
52 changes: 36 additions & 16 deletions spec-trait-impl/crates/spec-trait-macro/src/annotations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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<String>), Error> {
let var = if input.peek(Ident) {
to_string(&input.parse::<Ident>()?)
} else if input.peek(Lit) {
to_string(&input.parse::<Lit>()?)
} else {
return Err(Error::new(input.span(), "Expected identifier or literal"));
let method_call = match input.parse::<Expr>()? {
Expr::MethodCall(mc) => mc,
_ => {
return Err(Error::new(
input.span(),
"Expected a method call of the form `variable.function(args...)`",
));
}
};

input.parse::<Token![.]>()?; // 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::<Token![;]>()?; // 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
Expand Down Expand Up @@ -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! {
Expand Down