#macro #repeat #conditionally #piece #counter #sequence #sequential

conseq

条件重复序列中代码片段的宏

1 个不稳定版本

0.1.0 2024年6月9日
0.0.1 2024年6月9日

过程宏 中排名 #347

每月下载量 25

MIT/Apache

33KB
617

conseq!

github crates.io docs.rs

conseq! 宏,用于条件性地重复源代码片段,并在每次重复中将顺序数字计数器插入其中。

这是 seq! 的一个分支,增加了以下功能:

  • 条件应用重复
  • 在另一个 conseq! 宏内部使用 conseq!
[dependencies]
conseq = "0.1.0"
use conseq::conseq;

fn main() {
    let tuple = (1000, 100, 10);
    let mut sum = 0;
    
    // Expands to:
    //
    //     sum += tuple.0;
    //     sum += tuple.1;
    //     sum += tuple.2;
    //
    // This cannot be written using an ordinary for-loop because elements of
    // a tuple can only be accessed by their integer literal index, not by a
    // variable.
    conseq!(N in 0..=2 {
        sum += tuple.N;
    });
    
    assert_eq!(sum, 1110);
}
  • 如果输入的标记包含由 $[N]]( ... )* 包围的部分,其中 N 是数字计数器的名称,则只重复那部分。

  • 数字计数器可以粘贴到某些前缀的末尾以形成顺序标识符。

use conseq::conseq;

conseq!(N in 64..=127 {
    #[derive(Debug)]
    enum Demo {
        // Expands to Variant64, Variant65, ...
        $[N](
            Variant~N,
        )*
    }
});

fn main() {
    assert_eq!("Variant99", format!("{:?}", Demo::Variant99));
}
  • 您还可以在 $[ ... ] 内使用比较运算符(>、>=、<、<=、==)以条件性地重复序列。
use conseq::conseq;

fn main() {
    let tuple = (1000, 100, 10);
    let mut sum1 = 0;
    let mut sum2 = 0;
    let mut sum3 = 0;
    let mut sum4 = 0;
    let mut sum5 = 0;

    conseq!(N in 0..=2 {
        $[N](sum1 += tuple.N;)*
        $[N < 1](sum2 += tuple.N;)*
        $[N < 2](sum3 += tuple.N;)*
        $[N >= 1](sum4 += tuple.N;)*
        $[N == 2](sum5 += tuple.N;)*
    });

    assert_eq!(sum1, 1110);
    assert_eq!(sum2, 1000);
    assert_eq!(sum3, 1100);
    assert_eq!(sum4, 110);
    assert_eq!(sum5, 10);
}
  • 这里是一个更有用的例子
use conseq::conseq;

struct VarArgs<T> {
    tuple: T,
}

conseq!(N in 0..3 {
    impl<$[N < 1](T~N: PartialEq,)*> From<($[N < 1](T~N,)*)> for VarArgs<($[N < 1](T~N,)*)> {
        fn from(tuple: ($[N < 1](T~N,)*)) -> Self {
            VarArgs { tuple }
        }
    }
    impl<$[N < 2](T~N: PartialEq,)*> From<($[N < 2](T~N,)*)> for VarArgs<($[N < 2](T~N,)*)> {
        fn from(tuple: ($[N < 2](T~N,)*)) -> Self {
            VarArgs { tuple }
        }
    }
    impl<$[N < 3](T~N: PartialEq,)*> From<($[N < 3](T~N,)*)> for VarArgs<($[N < 3](T~N,)*)> {
        fn from(tuple: ($[N < 3](T~N,)*)) -> Self {
            VarArgs { tuple }
        }
    }
});

fn main() {
    let args1 = VarArgs::from((123,));
    let args2 = VarArgs::from((123, "text"));
    let args3 = VarArgs::from((123, "text", 1.5));
    assert_eq!(args1.tuple, (123,));
    assert_eq!(args2.tuple, (123, "text"));
    assert_eq!(args3.tuple, (123, "text", 1.5));
}
  • 您还可以在另一个 conseq! 宏内部使用 conseq!
use conseq::conseq;

conseq!(N in 1..=3 {
    struct Struct<$[N](T~N,)*> {
        $[N](field~N: T~N,)*
        another_field: String,
    }
    impl<$[N](T~N,)*> Struct<$[N](T~N,)*> {
        fn new($[N](field~N: T~N,)*) -> Self {
            let mut another_field = String::from("");
            // I know, this is a stupid example, 
            // but I wanted to demonstrate that you can actually do that 
            conseq!(L in 'a'..='z'{ another_field.push(L); });
            Struct { $[N](field~N,)* another_field }
        }
    }
});

fn main() {
    let s = Struct::new(1, 35.6, "abc");
    assert_eq!(s.field1, 1);
    assert_eq!(s.field2, 35.6);
    assert_eq!(s.field3, "abc");
    assert_eq!(s.another_field, "abcdefghijklmnopqrstuvwxyz");
}
  • 支持字节和字符范围:b'a'..=b'z''a'..='z'

  • 如果范围边界以二进制、八进制、十六进制或零填充的形式书写,则这些功能将在生成的任何标记中保留。

use conseq::conseq;

conseq!(P in 0x000..=0x00F {
    // expands to structs Pin000, ..., Pin009, Pin00A, ..., Pin00F
    struct Pin~P;
});

许可证

根据您的选择,在 Apache License, Version 2.0MIT许可证 下授权。
除非您明确说明,否则您根据Apache-2.0许可证定义的任何有意提交以包含在本软件包中的贡献,应按上述方式双许可,不得附加任何额外条款或条件。

无运行时依赖