#reactive #macro-derive #macro #derive #named-fields

dynamic-struct

为具有命名字段的struct创建基于推送的响应式属性的derive宏

1个不稳定版本

0.1.0 2023年1月7日

#7#named-fields

MIT/Apache

17KB
193

动态struct

为具有命名字段的struct创建基于推送的响应式属性的derive宏(仅限于具有命名字段的struct)。

为什么是推送式的?

懒的基于轮询的响应式系统通常需要包装值并添加RefCells或标志来缓存和更新值。基于事件的系统需要一个订阅模型。

添加基于推送的更改传播的管道是通过编译时宏完成的,生成的代码可以在编译期间内联,在运行时成为零成本抽象(就像在依赖关系更改时手动重新计算动态属性一样)

类型也可以保持不变,无需包装和解引用。

如何使用

1) 将其添加为Cargo文件中的依赖项

[dependencies]
dynamic-struct = "0.1"

2) 将derive宏添加到struct中并标记动态属性

use dynamic_struct::Dynamic;

#[derive(Dynamic)]
struct Demo {
    a: u32,
    b: u32,
    #[dynamic((a, b), calculate_c)]
    c: u32,
}

impl Demo {
    fn calculate_c(&mut self) {
        self.c = self.a + self.b
    }
}

属性的属性具有以下结构

#[dynamic(tuple of dependent property names, name of local method name)]

局部方法必须具有与以下匹配的调用签名:fn name(&mut self).

3) 使用生成的mutate函数更新属性

fn main() {
    let demo = Demo { a: 1, b: 2, c: 3 };

    dbg!(demo.c); //3
    demo.update_a(7);
    dbg!(demo.c); //9
}

工作原理

1) 创建函数以在属性更改时发出信号,其中填充了应调用的方法。

impl Demo {
    #[inline]
    pub fn updated_a(&mut self) {
        self.update_c();
    }
}

注意:不传播更改的属性将仍然创建,但将为空。

2) 为每个属性创建一个函数来更新属性

对于非动态属性,可以通过匹配字段类型的参数设置值,然后调用上述列出的字段更新函数。

impl Demo {
    #[inline]
    pub fn update_a(&mut self, a: u32) {
        self.a = a;
        self.updated_a();
    }
}

对于动态属性,通过调用指定的动态函数设置值,然后调用上述列出的字段更新函数。

impl Demo {
    #[inline]
    pub fn update_c(&mut self) {
        self.calculate_c();
        self.updated_c();
    }
}

注意:请小心不要创建循环依赖!

配置

可以通过声明结构体属性并重写前缀/后缀来自定义生成的函数名称。例如

#[derive(Dynamic)]
#[dynamic(setter_prefix = "set_", setter_suffix = "_value")]
struct MyStruct {
    a: u32,
    b: u32,
}

fn main() {
    let test = MyStruct { a: 1, b: 2 };

    test.set_a_value(3);
    test.set_b_value(4);
}

可以指定的属性包括

名称 类型 注释
updated_prefix 字符串 更新方法的名称前缀
updated_suffix 字符串 更新方法的名称后缀
setter_prefix 字符串 设置方法的前缀(非动态字段)
setter_suffix 字符串 设置方法的名称后缀(非动态字段)
update_prefix 字符串 更新方法的前缀(动态字段)
update_suffix 字符串 更新方法的后缀(动态字段)

依赖项

~2MB
~44K SLoC