From 2d846b10fa33d047a8e41d13fbc8b814787deec6 Mon Sep 17 00:00:00 2001 From: zjp Date: Wed, 1 Jun 2022 13:59:46 +0800 Subject: [PATCH] fix #2 --- .gitignore | 1 + src/dcl/variadic.md | 4 +-- src/dcl/variadic/Cargo.lock | 53 +++++++++++++++++++++++++++++++ src/dcl/variadic/Cargo.toml | 15 +++++++++ src/dcl/variadic/_impl/Cargo.toml | 12 +++++++ src/dcl/variadic/_impl/lib.rs | 53 +++++++++++++++++++++++++++++++ src/dcl/variadic/main.rs | 33 +++++++++++++++++++ 7 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 src/dcl/variadic/Cargo.lock create mode 100644 src/dcl/variadic/Cargo.toml create mode 100644 src/dcl/variadic/_impl/Cargo.toml create mode 100644 src/dcl/variadic/_impl/lib.rs create mode 100644 src/dcl/variadic/main.rs diff --git a/.gitignore b/.gitignore index 7585238..05ff2e4 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ book +target diff --git a/src/dcl/variadic.md b/src/dcl/variadic.md index 34273c4..01b9ce4 100644 --- a/src/dcl/variadic.md +++ b/src/dcl/variadic.md @@ -243,7 +243,7 @@ impl Parse for Input { let _: Comma = input.parse()?; let start = input.parse::()?.base10_parse()?; let _: Comma = input.parse()?; - let end: = input.parse::()?.base10_parse()?; + let end = input.parse::()?.base10_parse()?; let _: Comma = input.parse()?; let ident = input.parse()?; Ok(Input { name, start, end, ident }) @@ -253,7 +253,7 @@ impl Parse for Input { 宏充满了技巧,这需要观察和练习。如果你感兴趣的话,使用这段代码的展开结果[见此处][expanded]。 -当然,如果你的宏代码不够通用(不必复用),可以把这两个宏合并成一个宏。 +当然,如果你的宏代码不够通用(不必复用),可以把这两个宏合并成一个宏。完整项目代码见[此处](https://github.com/zjp-CN/rust-note/tree/main/src/dcl/variadic)。 然而,我想提醒你的是,本文的核心技巧是 trait 和泛型参数,宏只是锦上添花的内容。 diff --git a/src/dcl/variadic/Cargo.lock b/src/dcl/variadic/Cargo.lock new file mode 100644 index 0000000..79a6ff7 --- /dev/null +++ b/src/dcl/variadic/Cargo.lock @@ -0,0 +1,53 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "_impl" +version = "0.1.0" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" + +[[package]] +name = "variadic" +version = "0.1.0" +dependencies = [ + "_impl", +] diff --git a/src/dcl/variadic/Cargo.toml b/src/dcl/variadic/Cargo.toml new file mode 100644 index 0000000..e35ba37 --- /dev/null +++ b/src/dcl/variadic/Cargo.toml @@ -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"] + diff --git a/src/dcl/variadic/_impl/Cargo.toml b/src/dcl/variadic/_impl/Cargo.toml new file mode 100644 index 0000000..de681aa --- /dev/null +++ b/src/dcl/variadic/_impl/Cargo.toml @@ -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" diff --git a/src/dcl/variadic/_impl/lib.rs b/src/dcl/variadic/_impl/lib.rs new file mode 100644 index 0000000..8390cf5 --- /dev/null +++ b/src/dcl/variadic/_impl/lib.rs @@ -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 $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 { + use syn::token::Comma; + let start = input.parse::()?.base10_parse()?; + let _: Comma = input.parse()?; + let end = input.parse::()?.base10_parse()?; + let _: Comma = input.parse()?; + let ident = input.parse()?; + Ok(Input { start, end, ident }) + } +} diff --git a/src/dcl/variadic/main.rs b/src/dcl/variadic/main.rs new file mode 100644 index 0000000..43d6c7f --- /dev/null +++ b/src/dcl/variadic/main.rs @@ -0,0 +1,33 @@ +#![allow(unused)] + +pub struct Ui {} + +pub trait Component { + fn call(&self, ui: &mut Ui, params: Params, content: Content); +} + +_impl::all_tuples!(1, 16, P); + +pub fn memoize(ui: &mut Ui, component: Comp, params: Params, + content: Content) + where Params: PartialEq + Clone + 'static, + Content: FnOnce(&mut Ui), + Comp: Component +{ + 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), |_| {}); +}