#table #field #receiver #re-exports #macro #system #snec

snec_macros

Snec crate的宏,旨在通过Snec的重导出使用

2个版本 (1个稳定版)

1.0.0 2020年11月8日
0.1.0 2020年8月26日

#31 in #receiver


用于snec

MIT/Apache

35KB
807

Snec

Crates.io Docs.rs Build Status

具有编译时字段查找和修改通知功能的配置系统。

概述

Snec是一个关注编译时保证以及通知运行系统配置值已更改的配置系统。大部分的功能都通过宏实现,这也是为什么它们默认导出的原因。

虽然不提供内置的序列化支持,但该架构本身是序列化无关的——使用Serde和Snec进行相同的配置表结构将工作得很好。

Snec的架构包括以下关键组件

  • 配置表 — 包含程序配置数据的结构。配置表实现Get特质以访问其字段,这使得它们可以分配Handle给其字段。句柄确保分配的接收器在字段更改时被通知,除非它明确被提示执行静默修改。
  • 条目 — 实现Entry特质的空类型(没有可能值的类型),代表配置表内字段的标识符。
  • 接收器 — 实现Receiver特质的类型,它将在配置表中感兴趣的字段被修改时接收通知。

基本示例

use snec::{ConfigTable, Entry, GetExt as _};
use std::time::{SystemTime, Duration};
#[derive(ConfigTable)]
struct MyConfigTable {
    #[snec]
    when: SystemTime,
    #[snec]
    who: String,
    #[snec]
    in_which_country: String,
}
let mut config_table = MyConfigTable {
    when: SystemTime::UNIX_EPOCH + Duration::from_secs(566_200_800),
    who: "Jeremy".to_string(),
    in_which_country: "USA".to_string(),
};

// To access the fields of our config table, we need to use the get_handle method from
// the GetExt trait (which is a nicer way to use the Get trait). The `entries` part is
// a module generated by the `#[derive(ConfigTable)]`. In most cases, it's desirable
// to reexport the contents of the module in a public module with a different name and
// some documentation, or simply in the containing module if you want the entry
// identifiers to be in the same module as the config table.
let mut handle = config_table.get_handle_to::<entries::InWhichCountry>();
// After we got the handle, we can use it to get a
// mutable reference to the field and modify it:
{
    let mut in_which_country = handle.modify();
    *in_which_country = "Britain".to_string();
}
// The reason why we put that in a scope and why we had to do this entire two-step process
// is because otherwise we'd implicitly avoid notifying any receivers, which is something
// that we'll look into in the next example. Since we don't have any, it won't really
// hurt if we did this as well:
{
    let in_which_country = handle.modify_silently();
    *in_which_country = "Australia".to_string();
}

使用接收器

use snec::{ConfigTable, Receiver, Entry, GetExt as _};
use std::time::{SystemTime, Duration};
#[derive(ConfigTable)]
#[snec(
    // Any expression can be used in the braces. After the colon, the type is supplied.
    receiver({MyReceiver}: MyReceiver)
)]
struct MyConfigTable {
    #[snec]
    which_year: i64,
    #[snec(entry, receiver({snec::EmptyReceiver}: snec::EmptyReceiver))]
    why: String,
    #[snec]
    random_integer_that_i_like: u128,
}

struct MyReceiver;
impl Receiver<entries::RandomIntegerThatILike> for MyReceiver {
    fn receive(&mut self, new_value: &u128) {
        println!("My integer has been changed to {}!!", new_value)
    }
}
impl Receiver<entries::WhichYear> for MyReceiver {
    fn receive(&mut self, new_value: &i64) {
        println!("Resceduled to {}", new_value)
    }
}

let mut config_table = MyConfigTable {
    which_year: 1987,
    why: "Accident".to_string(),
    random_integer_that_i_like: 687_800,
};
// Now we have receivers which will immediately react to any changes in the values:
let mut handle = config_table.get_handle_to::<entries::WhichYear>();
{
    let mut which_year = handle.modify();
    *which_year = 1983;
}
// When the scope ends, the `which_year` guard is dropped and the receiver is informed.

依赖项

~1.5MB
~35K SLoC