Crate invoke_impl
source · [−]Expand description
This crate revolves around the single attribute procedural macro invoke_impl, which when applied to a struct impl block where all the methods or associated functions share identical signatures will generate functions that help automate the calling process for invoking these functions.
Six functions are generated: invoke_all, invoke_subset, invoke_all_enumerated, invoke_all_enum, invoke_enumerated, and invoke_enum. When the associated functions or methods of the impl block have a return type, these functions all take closure parameters that receive this return type. Additionally, the closures for invoke_all_enumerated and invoke_enumerated take a usize and the closures for invoke_all_enum and invoke_enum take an enum of the type of the macro generated enum, which can be used within the closure to determine specifically which function is being invoked at a given point in time.
When there is no return type, invoke_all and invoke_subset do not take a closure, while invoke_all_enumerated and invoke_enumerated take a closure that takes usize and invoke_all_enum and invoke_enum take a closure that takes the type of the macro-generated enum.
invoke_impl takes two arguments, name (expecting a string literal) and clone (expecting a list of int literals). Name specifiers an optional name to be appended to the identifiers of generated code, while clone indicates which 0-indexed parameters of the functions or methods in the impl block are to be cloned instead of directly forwarded.
Additionally, invoke_impl adds two const fields to the impl block it is on: a list of &str copies of the identifiers of the invocable functions contained in the impl block, and a usize of the total count of invocable functions.
For example:
struct Tester1;
#[invoke_impl]
impl Tester1 {
pub fn fn1(i: i32) -> i32 {
i
}
pub fn fn2(i: i32) -> i32 {
i
}
pub fn fn3(i: i32) -> i32 {
i
}
}
is expanded into the following code:
struct Tester1;
impl Tester1 {
pub fn fn1(i: i32) -> i32 {
i
}
pub fn fn2(i: i32) -> i32 {
i
}
pub fn fn3(i: i32) -> i32 {
i
}
pub fn invoke_all(i: i32, mut consumer: impl FnMut(i32)) {
consumer(Tester1::fn1(i));
consumer(Tester1::fn2(i));
consumer(Tester1::fn3(i));
}
pub fn invoke_subset(
i: i32,
mut consumer: impl FnMut(i32),
mut invoke_impl_iter: impl Iterator<Item = usize>,
) {
for invoke_impl_i in invoke_impl_iter {
match invoke_impl_i {
0usize => consumer(Tester1::fn1(i)),
1usize => consumer(Tester1::fn2(i)),
2usize => consumer(Tester1::fn3(i)),
_ => ::core::panicking::panic_fmt(::core::fmt::Arguments::new_v1(
&["Iter contains invalid function index!"],
&[],
)),
}
}
}
pub fn invoke_all_enumerated(i: i32, mut consumer: impl FnMut(usize, i32)) {
consumer(0usize, Tester1::fn1(i));
consumer(1usize, Tester1::fn2(i));
consumer(2usize, Tester1::fn3(i));
}
pub fn invoke_all_enum(i: i32, mut consumer: impl FnMut(Tester1_invoke_impl_enum, i32)) {
consumer(Tester1_invoke_impl_enum::fn1, Tester1::fn1(i));
consumer(Tester1_invoke_impl_enum::fn2, Tester1::fn2(i));
consumer(Tester1_invoke_impl_enum::fn3, Tester1::fn3(i));
}
pub fn invoke_enumerated(
i: i32,
mut consumer: impl FnMut(usize, i32),
mut invoke_impl_iter: impl Iterator<Item = usize>,
) {
for invoke_impl_i in invoke_impl_iter {
match invoke_impl_i {
0usize => {
consumer(0usize, Tester1::fn1(i));
}
1usize => {
consumer(1usize, Tester1::fn2(i));
}
2usize => {
consumer(2usize, Tester1::fn3(i));
}
_ => ::core::panicking::panic_fmt(::core::fmt::Arguments::new_v1(
&["Iter contains invalid function index!"],
&[],
)),
}
}
}
pub fn invoke_enum(
i: i32,
mut consumer: impl FnMut(Tester1_invoke_impl_enum, i32),
mut invoke_impl_iter: impl Iterator<Item = Tester1_invoke_impl_enum>,
) {
for invoke_impl_i in invoke_impl_iter {
match invoke_impl_i {
Tester1_invoke_impl_enum::fn1 => {
consumer(Tester1_invoke_impl_enum::fn1, Tester1::fn1(i));
}
Tester1_invoke_impl_enum::fn2 => {
consumer(Tester1_invoke_impl_enum::fn2, Tester1::fn2(i));
}
Tester1_invoke_impl_enum::fn3 => {
consumer(Tester1_invoke_impl_enum::fn3, Tester1::fn3(i));
}
}
}
}
pub const METHOD_COUNT: usize = 3usize;
pub const METHOD_LIST: [&'static str; 3usize] = ["fn1", "fn2", "fn3"];
}
pub enum Tester1_invoke_impl_enum {
fn1,
fn2,
fn3,
}
#[automatically_derived]
#[allow(unused_qualifications)]
impl ::core::fmt::Debug for Tester1_invoke_impl_enum {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match (&*self,) {
(&Tester1_invoke_impl_enum::fn1,) => ::core::fmt::Formatter::write_str(f, "fn1"),
(&Tester1_invoke_impl_enum::fn2,) => ::core::fmt::Formatter::write_str(f, "fn2"),
(&Tester1_invoke_impl_enum::fn3,) => ::core::fmt::Formatter::write_str(f, "fn3"),
}
}
}
#[automatically_derived]
#[allow(unused_qualifications)]
impl ::core::clone::Clone for Tester1_invoke_impl_enum {
#[inline]
fn clone(&self) -> Tester1_invoke_impl_enum {
{
*self
}
}
}
#[automatically_derived]
#[allow(unused_qualifications)]
impl ::core::marker::Copy for Tester1_invoke_impl_enum {}
impl Tester1_invoke_impl_enum {
pub fn iter() -> impl Iterator<Item = &'static Tester1_invoke_impl_enum> {
use Tester1_invoke_impl_enum::*;
static members: [Tester1_invoke_impl_enum; 3usize] = [fn1, fn2, fn3];
members.iter()
}
}
impl TryFrom<&str> for Tester1_invoke_impl_enum {
type Error = &'static str;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"fn1" => Ok(Self::fn1),
"fn2" => Ok(Self::fn2),
"fn3" => Ok(Self::fn3),
_ => Err("Input str does not match any enums in Self!"),
}
}
}
impl From<Tester1_invoke_impl_enum> for &str {
fn from(en: Tester1_invoke_impl_enum) -> Self {
use Tester1_invoke_impl_enum::*;
match en {
fn1 => "fn1",
fn2 => "fn2",
fn3 => "fn3",
}
}
}
Attribute Macros
Proc macro which appends six different functions to a struct impl block that each represent different ways of invoking functions or methods implemented in that impl block, as well as two associated constants.