embassy 中的宏 check_at_most_one 解析

embassy中有个宏,check_at_most_one,这个宏通过生成编译时条件编译指令来检查用户是否只配置了一个编译条件。具体来说,它会生成一系列的 #[cfg] 属性,这些属性会在编译时进行检查。如果发现有多个 feature 同时启用,就会触发编译错误。

macro_rules! check_at_most_one {
    (@amo [$($feats:literal)*] [] [$($res:tt)*]) => {
        #[cfg(any($($res)*))]
        compile_error!(concat!("At most one of these features can be enabled at the same time:", $(" `", $feats, "`",)*));
    };
    (@amo $feats:tt [$curr:literal $($rest:literal)*] [$($res:tt)*]) => {
        check_at_most_one!(@amo $feats [$($rest)*] [$($res)* $(all(feature=$curr, feature=$rest),)*]);
    };
    ($($f:literal),*$(,)?) => {
        check_at_most_one!(@amo [$($f)*] [$($f)*] []);
    };
}
check_at_most_one!(
    "arch-avr",
    "arch-cortex-m",
    "arch-riscv32",
    "arch-std",
    "arch-wasm",
    "arch-spin",
);

以上面的使用例子来分析,check_at_most_one! 第一次调用时会走第三个分支,

($($f:literal),*$(,)?) => {
    check_at_most_one!(@amo [$($f)*] [$($f)*] []);
};

这个分支比较简单,前面添加@amo,是为了迭代调用时进入另外的分支,接着将传入的参数生成两个一样的数组,第一个数组在后续循环中会保持不变,第二个数组用来生成所有all()组合用的,第三个空数组是用来存储输出数据用的,调用展开为:

check_at_most_one!(@amo ["arch-avr", "arch-cortex-m", "arch-riscv32", "arch-std", "arch-wasm", "arch-spin"] ["arch-avr", "arch-cortex-m", "arch-riscv32", "arch-std", "arch-wasm", "arch-spin"] []);

再次轮询时会走第二分支,进入递归处理流程

(@amo $feats:tt [$curr:literal $($rest:literal)*] [$($res:tt)*]) => {
    check_at_most_one!(@amo $feats [$($rest)*] [$($res)* $(all(feature=$curr, feature=$rest),)*]);
};

这个有点复杂,一个个分析

$feats:tt  这个会取得第一个数组的全部值,后续递归也一直保持不变

[$curr:literal $($rest:literal)*] 每次递归时,从第二个数组中,$curr:literal 取出第一个项,$($rest:literal)*为后续剩余所有的项,

[$($res:tt)*]为第三个数组展开,第一次迭代为空数组

第一次调用展开为

check_at_most_one!(@amo ["arch-avr", "arch-cortex-m", "arch-riscv32", "arch-std", "arch-wasm", "arch-spin"] 
["arch-cortex-m", "arch-riscv32", "arch-std", "arch-wasm", "arch-spin"] 
[all(feature="arch-avr", feature="arch-cortex-m"),
all(feature="arch-avr", feature="arch-riscv32"),
all(feature="arch-avr", feature="arch-std"),
all(feature="arch-avr", feature="arch-wasm"),
all(feature="arch-avr", feature="arch-spin"),]);

第二次展开为:

check_at_most_one!(@amo ["arch-avr", "arch-cortex-m", "arch-riscv32", "arch-std", "arch-wasm", "arch-spin"] 
["arch-riscv32", "arch-std", "arch-wasm", "arch-spin"] 
[all(feature="arch-avr", feature="arch-cortex-m"),
all(feature="arch-avr", feature="arch-riscv32"),
all(feature="arch-avr", feature="arch-std"),
all(feature="arch-avr", feature="arch-wasm"),
all(feature="arch-avr", feature="arch-spin"),

//以下为第二次迭代新添加的项
all(feature="arch-cortex-m", feature="arch-riscv32"),
all(feature="arch-cortex-m", feature="arch-std"),
all(feature="arch-cortex-m", feature="arch-wasm"),
all(feature="arch-cortex-m", feature="arch-spin"),]);

以此类推,当迭代到第二个数组为空时,就会进入第一个分支:

    (@amo [$($feats:literal)*] [] [$($res:tt)*]) => {
        #[cfg(any($($res)*))]
        compile_error!(concat!("At most one of these features can be enabled at the same time:", $(" `", $feats, "`",)*));
    };

这里展开相当于是:

#[cfg(any(
    all(feature="arch-avr", feature="arch-cortex-m"),
    all(feature="arch-avr", feature="arch-riscv32"),
    all(feature="arch-cortex-m", feature="arch-riscv32"),
    // ... 其他组合
))]
compile_error!("At most one of these features can be enabled at the same time: `arch-avr` `arch-cortex-m` `arch-riscv32` `arch-std` `arch-wasm` `arch-spin`");

这样就意味着,如果这个组合里面,用户同时打开多个feature,编译就会报错。保证用户只能打开其中一个feature,这个宏的设计方式挺精妙。可以在有多个互斥feature的场景下拿来直接使用。

prsa_data_2010.1.12014.12.31.csv是一个具体日期范围内的空气质量数据文件。文件名中的"prsa"是指"Beijing PM2.5 Data of US Embassy"的缩写,代表了美国大使馆在北京收集的PM2.5数据。 该文件包含了从2010年1月1日到2014年12月31日的连续时间段内的空气质量数据。PM2.5是指空气中颗粒物污染物的细颗粒物,直径小于2.5微米。这些颗粒物对人体健康非常有害,特别是在吸入时,可能引发呼吸系统疾病和心血管疾病。 该数据文件的主要目的是记录北京市不同时间段内的空气质量水平,以便进行监测和分析。数据中包括了每小时的PM2.5浓度、站点名称、位置坐标、记录时间等信息。通过分析这些数据,可以了解北京市不同时间段内的空气质量状况,检测污染源、观察不同季节和天气条件下的变化趋势,并为制定环境保护政策提供科学依据。 此外,该数据文件还可以用于公众教育和意识提高。人们可以查看这些数据,了解北京市某个特定时间段内的空气质量状况,并在必要时采取相应的防护措施。通过公开发布这些数据,还可以促进公众对空气质量问题的关注,推动环境保护和减少污染的意识。 总而言之,prsa_data_2010.1.12014.12.31.csv是一个重要的空气质量数据文件,记录了北京市2010年1月1日至2014年12月31日的PM2.5浓度和其他相关信息。这些数据对于环境监测、科学研究和公众教育都具有重要意义。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值