Skip to content

Commit

Permalink
fix #2
Browse files Browse the repository at this point in the history
  • Loading branch information
zjp-CN committed Jun 1, 2022
1 parent 339cd74 commit 2d846b1
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 2 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
book
target
4 changes: 2 additions & 2 deletions src/dcl/variadic.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ impl Parse for Input {
let _: Comma = input.parse()?;
let start = input.parse::<LitInt>()?.base10_parse()?;
let _: Comma = input.parse()?;
let end: = input.parse::<LitInt>()?.base10_parse()?;
let end = input.parse::<LitInt>()?.base10_parse()?;
let _: Comma = input.parse()?;
let ident = input.parse()?;
Ok(Input { name, start, end, ident })
Expand All @@ -253,7 +253,7 @@ impl Parse for Input {

宏充满了技巧,这需要观察和练习。如果你感兴趣的话,使用这段代码的展开结果[见此处][expanded]

当然,如果你的宏代码不够通用(不必复用),可以把这两个宏合并成一个宏。
当然,如果你的宏代码不够通用(不必复用),可以把这两个宏合并成一个宏。完整项目代码见[此处](https://github.com/zjp-CN/rust-note/tree/main/src/dcl/variadic)

然而,我想提醒你的是,本文的核心技巧是 trait 和泛型参数,宏只是锦上添花的内容。

Expand Down
53 changes: 53 additions & 0 deletions src/dcl/variadic/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions src/dcl/variadic/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "variadic"
version = "0.1.0"
edition = "2021"

[[bin]]
name = "variadic"
path = "main.rs"

[dependencies]
_impl = { path = "./_impl" }

[workspace]
members = ["_impl"]

12 changes: 12 additions & 0 deletions src/dcl/variadic/_impl/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "_impl"
version = "0.1.0"
edition = "2021"

[lib]
path = "lib.rs"
proc-macro = true

[dependencies]
quote = "1"
syn = "1"
53 changes: 53 additions & 0 deletions src/dcl/variadic/_impl/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::{
parse::{Parse, ParseStream},
parse_macro_input, Ident, LitInt, Result,
};

#[proc_macro]
pub fn all_tuples(input: TokenStream) -> TokenStream {
let Input { start, end, ident } = parse_macro_input!(input);
let items = (start..end + 1).map(|n| {
let ids = (start..n + 1).map(|n| format_ident!("{ident}{n}"));
quote!(impl_component! {#(#ids),*})
});
let macro_impl_component = quote!(
macro_rules! impl_component {
($($P:ident),*) => {
impl<F, $($P,)* Content> $crate::Component<( $($P,)* ), Content> for F
where F: Fn(&mut $crate::Ui, $($P,)* Content),
$( $P: ::std::cmp::PartialEq + ::std::clone::Clone + 'static, )*
Content: ::std::ops::FnOnce(&mut Ui)
{

fn call(&self, ui: &mut $crate::Ui, params: ( $($P,)* ), content: Content) {
#[allow(non_snake_case)]
let ($($P,)*) = params;
self(ui, $($P,)* content)
}
}
};
}
);
quote!(#macro_impl_component #(#items)*).into()
}

struct Input {
start: u8,
end: u8,
ident: Ident,
}

impl Parse for Input {
#[rustfmt::skip]
fn parse(input: ParseStream) -> Result<Self> {
use syn::token::Comma;
let start = input.parse::<LitInt>()?.base10_parse()?;
let _: Comma = input.parse()?;
let end = input.parse::<LitInt>()?.base10_parse()?;
let _: Comma = input.parse()?;
let ident = input.parse()?;
Ok(Input { start, end, ident })
}
}
33 changes: 33 additions & 0 deletions src/dcl/variadic/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#![allow(unused)]

pub struct Ui {}

pub trait Component<Params, Content> {
fn call(&self, ui: &mut Ui, params: Params, content: Content);
}

_impl::all_tuples!(1, 16, P);

pub fn memoize<Params, Content, Comp>(ui: &mut Ui, component: Comp, params: Params,
content: Content)
where Params: PartialEq + Clone + 'static,
Content: FnOnce(&mut Ui),
Comp: Component<Params, Content>
{
component.call(ui, params, content);
}

fn comp1(ui: &mut Ui, a: u8, f: impl FnOnce(&mut Ui)) { f(ui); }
fn comp_(ui: &mut Ui, a: &str, f: impl FnOnce(&mut Ui)) { f(ui); }
fn comp2(ui: &mut Ui, a: u8, b: u32, f: impl FnOnce(&mut Ui)) { f(ui); }
fn comp3(ui: &mut Ui, a: u8, b: u32, c: u64, f: impl FnOnce(&mut Ui)) { f(ui); }
fn comp4(ui: &mut Ui, a: u8, b: u32, c: u64, d: usize, f: impl FnOnce(&mut Ui)) { f(ui); }

fn main() {
let mut ui = Ui {};
memoize(&mut ui, comp1, (1,), |_| {});
memoize(&mut ui, comp_, ("",), |_| {});
memoize(&mut ui, comp2, (2, 3), |_| {});
memoize(&mut ui, comp3, (1, 2, 3), |_| {});
memoize(&mut ui, comp4, (0, 1, 2, 3), |_| {});
}

0 comments on commit 2d846b1

Please sign in to comment.