Skip to content

Commit

Permalink
Replace uses of expr & E with arg & Arg
Browse files Browse the repository at this point in the history
"Input expression" is more descriptive than "argument".
  • Loading branch information
ozars committed Apr 9, 2024
1 parent 42d72d6 commit 38434c5
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 76 deletions.
25 changes: 13 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,20 @@ which this macro is called.

use specialized_dispatch::specialized_dispatch;

fn example<Arg>(arg: Arg) -> String {
fn example<E>(expr: E) -> String {
specialized_dispatch!(
// Type of the argument -> return type.
Arg -> String,
// Type of the expression -> return type.
E -> String,
// Defaut implementation. At least one default value is required.
// Referring to values other than the argument is not supported.
// Referring to values other than the provided argument is not
// supported.
default fn <T>(_: T) => format!("default value"),
// Specialization for concrete type u8.
fn (v: u8) => format!("u8: {}", v),
// Specialization for concrete type u16.
fn (v: u16) => format!("u16: {}", v),
// The argument to the dispatched function. This can be an arbitrary expression.
arg,
// The expression for passing to above specializations.
expr,
)
}

Expand All @@ -61,7 +62,7 @@ implementation detail. This example is provided to demonstrate how it works unde
hood.

```rust
fn example<T>(t: T) -> String {
fn example<E>(expr: E) -> String {
trait SpecializedDispatchCall<T> {
fn dispatch(t: T) -> String;
}
Expand All @@ -84,7 +85,7 @@ fn example<T>(t: T) -> String {
}
}

<Arg as SpecializedDispatchCall<Arg>>::dispatch(arg)
<E as SpecializedDispatchCall<E>>::dispatch(expr)
}
```

Expand All @@ -108,16 +109,16 @@ use std::fmt::Display;

use specialized_dispatch::specialized_dispatch;

// The argument type must also bind to the same trait.
fn example<Arg: Display>(arg: Arg) -> String {
// The expression type must also bind to the same trait.
fn example<E: Display>(expr: E) -> String {
specialized_dispatch!(
Arg -> String,
E -> String,
// Notice the trait bound.
default fn <T: Display>(v: T) => format!("default value: {}", v),
// Note that specializations also need to satisfy the same bound.
fn (v: u8) => format!("u8: {}", v),
fn (v: u16) => format!("u16: {}", v),
arg,
expr,
)
}

Expand Down
13 changes: 7 additions & 6 deletions examples/simple_example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@

use specialized_dispatch::specialized_dispatch;

fn example<Arg>(arg: Arg) -> String {
fn example<E>(expr: E) -> String {
specialized_dispatch!(
// Type of the argument -> return type.
Arg -> String,
// Type of the expression -> return type.
E -> String,
// Defaut implementation. At least one default value is required.
// Referring to values other than the argument is not supported.
// Referring to values other than the provided argument is not
// supported.
default fn <T>(_: T) => format!("default value"),
// Specialization for concrete type u8.
fn (v: u8) => format!("u8: {}", v),
// Specialization for concrete type u16.
fn (v: u16) => format!("u16: {}", v),
// The argument to the dispatched function. This can be an arbitrary expression.
arg,
// The expression for passing to above specializations.
expr,
)
}

Expand Down
92 changes: 46 additions & 46 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ use syn::{
Expr, GenericParam, Ident, Result, Token, Type,
};

/// Parses either an identifier or an underscore for the argument in arms of specialized dispatch
/// macro.
/// Parses either an identifier or an underscore for the input expression in arms of specialized
/// dispatch macro.
#[derive(Debug, Eq, PartialEq)]
enum ArgNameExpr {
enum InputExprName {
Ident(Ident),
UnderScore(Token![_]),
}

impl Parse for ArgNameExpr {
impl Parse for InputExprName {
fn parse(input: ParseStream) -> Result<Self> {
if input.peek(Ident) {
Ok(Self::Ident(input.parse()?))
Expand All @@ -31,7 +31,7 @@ impl Parse for ArgNameExpr {
}
}

impl ToTokens for ArgNameExpr {
impl ToTokens for InputExprName {
fn to_tokens(&self, tokens: &mut TokenStream2) {
match self {
Self::Ident(ident) => ident.to_tokens(tokens),
Expand Down Expand Up @@ -60,8 +60,8 @@ impl ToTokens for ArgNameExpr {
struct DispatchArmExpr {
default: Option<Token![default]>,
generic_params: Option<Punctuated<GenericParam, Token![,]>>,
arg_name: ArgNameExpr,
arg_type: Type,
input_expr_name: InputExprName,
input_expr_type: Type,
body: Expr,
}

Expand All @@ -71,28 +71,28 @@ impl Parse for DispatchArmExpr {
let _ = input.parse::<Token![fn]>()?;
let generic_params = if input.peek(Token![<]) {
let _ = input.parse::<Token![<]>()?;
let generic_args =
let generic_params =
Punctuated::<GenericParam, Token![,]>::parse_separated_nonempty(input)?;
let _ = input.parse::<Token![>]>()?;
Some(generic_args)
Some(generic_params)
} else {
None
};
let args_content;
let _ = parenthesized!(args_content in input);
let arg_name = args_content.parse()?;
let _ = args_content.parse::<Token![:]>()?;
let arg_type = args_content.parse()?;
if !args_content.is_empty() {
return Err(args_content.error("unexpected token"));
let input_expr_content;
let _ = parenthesized!(input_expr_content in input);
let input_expr_name = input_expr_content.parse()?;
let _ = input_expr_content.parse::<Token![:]>()?;
let input_expr_type = input_expr_content.parse()?;
if !input_expr_content.is_empty() {
return Err(input_expr_content.error("unexpected token"));
}
let _ = input.parse::<Token![=>]>()?;
let body = input.parse()?;
Ok(Self {
default,
generic_params,
arg_name,
arg_type,
input_expr_name,
input_expr_type,
body,
})
}
Expand All @@ -104,18 +104,18 @@ impl Parse for DispatchArmExpr {
/// # Example Input
///
/// ```
/// arg,
/// Arg -> String,
/// E -> String,
/// fn <T>(_: T) => format!("default value"),
/// fn (v: u8) => format!("u8: {}", v),
/// fn (v: u16) => format!("u16: {}", v),
/// expr,
/// ```
#[derive(Debug, Eq, PartialEq)]
struct SpecializedDispatchExpr {
from_type: Type,
to_type: Type,
arms: Vec<DispatchArmExpr>,
arg_expr: Expr,
input_expr: Expr,
}

fn parse_punctuated_arms(input: &ParseStream) -> Result<Punctuated<DispatchArmExpr, Token![,]>> {
Expand Down Expand Up @@ -143,13 +143,13 @@ impl Parse for SpecializedDispatchExpr {
let _ = input.parse::<Token![,]>()?;
let arms = parse_punctuated_arms(&input)?.into_iter().collect();
let _ = input.parse::<Token![,]>()?;
let arg_expr = input.parse()?;
let input_expr = input.parse()?;
let _ = input.parse::<Token![,]>().ok();
Ok(Self {
from_type,
to_type,
arms,
arg_expr,
input_expr,
})
}
}
Expand All @@ -170,25 +170,25 @@ fn generate_trait_implementation(
default: Option<&Token![default]>,
trait_name: &Ident,
generic_params: Option<&Punctuated<GenericParam, Token![,]>>,
arg_type: &Type,
arg_name: &ArgNameExpr,
input_expr_type: &Type,
input_expr_name: &InputExprName,
return_type: &Type,
body: &Expr,
) -> TokenStream2 {
let generics = generic_params.map(|g| quote! {<#g>});
quote! {
impl #generics #trait_name<#arg_type> for #arg_type {
#default fn dispatch(#arg_name: #arg_type) -> #return_type {
impl #generics #trait_name<#input_expr_type> for #input_expr_type {
#default fn dispatch(#input_expr_name: #input_expr_type) -> #return_type {
#body
}
}
}
}

/// Generates the dispatch call to the helper trait.
fn generate_dispatch_call(from_type: &Type, trait_name: &Ident, arg: &Expr) -> TokenStream2 {
fn generate_dispatch_call(from_type: &Type, trait_name: &Ident, input_expr: &Expr) -> TokenStream2 {
quote! {
<#from_type as #trait_name<#from_type>>::dispatch(#arg)
<#from_type as #trait_name<#from_type>>::dispatch(#input_expr)
}
}

Expand All @@ -204,14 +204,14 @@ impl ToTokens for SpecializedDispatchExpr {
arm.default.as_ref(),
&trait_name,
arm.generic_params.as_ref(),
&arm.arg_type,
&arm.arg_name,
&arm.input_expr_type,
&arm.input_expr_name,
&self.to_type,
&arm.body,
));
}

let dispatch_call = generate_dispatch_call(&self.from_type, &trait_name, &self.arg_expr);
let dispatch_call = generate_dispatch_call(&self.from_type, &trait_name, &self.input_expr);

tokens.extend(quote! {
{
Expand Down Expand Up @@ -245,8 +245,8 @@ mod tests {
DispatchArmExpr {
default: None,
generic_params: None,
arg_name: parse_quote!(v),
arg_type: parse_quote!(u8),
input_expr_name: parse_quote!(v),
input_expr_type: parse_quote!(u8),
body: parse_quote!(format!("u8: {}", v)),
}
);
Expand All @@ -260,8 +260,8 @@ mod tests {
DispatchArmExpr {
default: Some(Default::default()),
generic_params: Some(parse_quote!(T)),
arg_name: parse_quote!(_),
arg_type: parse_quote!(T),
input_expr_name: parse_quote!(_),
input_expr_type: parse_quote!(T),
body: parse_quote!(format!("default value")),
}
);
Expand All @@ -270,41 +270,41 @@ mod tests {
#[test]
fn parse_specialized_dispatch_expr() {
let expr: SpecializedDispatchExpr = parse_quote! {
Arg -> String,
E -> String,
default fn <T>(_: T) => format!("default value"),
fn (v: u8) => format!("u8: {}", v),
fn (v: u16) => format!("u16: {}", v),
arg,
expr,
};
assert_eq!(
expr,
SpecializedDispatchExpr {
from_type: parse_quote!(Arg),
from_type: parse_quote!(E),
to_type: parse_quote!(String),
arms: vec![
DispatchArmExpr {
default: Some(Default::default()),
generic_params: Some(parse_quote!(T)),
arg_name: parse_quote!(_),
arg_type: parse_quote!(T),
input_expr_name: parse_quote!(_),
input_expr_type: parse_quote!(T),
body: parse_quote!(format!("default value")),
},
DispatchArmExpr {
default: None,
generic_params: None,
arg_name: parse_quote!(v),
arg_type: parse_quote!(u8),
input_expr_name: parse_quote!(v),
input_expr_type: parse_quote!(u8),
body: parse_quote!(format!("u8: {}", v)),
},
DispatchArmExpr {
default: None,
generic_params: None,
arg_name: parse_quote!(v),
arg_type: parse_quote!(u16),
input_expr_name: parse_quote!(v),
input_expr_type: parse_quote!(u16),
body: parse_quote!(format!("u16: {}", v)),
},
],
arg_expr: parse_quote!(arg),
input_expr: parse_quote!(expr),
}
);
}
Expand Down
Loading

0 comments on commit 38434c5

Please sign in to comment.