Crates.io | conseq |
lib.rs | conseq |
version | 0.1.0 |
source | src |
created_at | 2024-06-09 13:52:17.133561 |
updated_at | 2024-06-09 17:51:32.299304 |
description | Macro to conditionally repeat a piece of code in a sequence. |
homepage | |
repository | https://github.com/pstroka/conseq |
max_upload_size | |
id | 1266399 |
size | 43,972 |
conseq!
A conseq!
macro to conditionally repeat a fragment of source code and
substitute into each repetition a sequential numeric counter.
This is a fork of seq!
, extended with the following features:
apply the repetitions conditionally
use the conseq!
macro inside another conseq!
macro
[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);
}
If the input tokens contain a section surrounded by $[N](
... )*
, where N is the name of
the numeric counter, then only that part is repeated.
The numeric counter can be pasted onto the end of some prefix to form sequential identifiers.
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));
}
$[
... ]
to repeat the
sequence conditionally.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!
macro inside another conseq!
macrouse 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");
}
Byte and character ranges are supported: b'a'..=b'z'
, 'a'..='z'
.
If the range bounds are written in binary, octal, hex, or with zero padding, those features are preserved in any generated tokens.
use conseq::conseq;
conseq!(P in 0x000..=0x00F {
// expands to structs Pin000, ..., Pin009, Pin00A, ..., Pin00F
struct Pin~P;
});