#arc #attributes #rwlock #async #read-write #lazy-evaluation #data-structures

warcrwlock

这是一个Rust的crate,它为结构和特质提供了属性宏。使用底层的异步引用(Arc)和异步读写(RWlock)控制元素重写代码。

11个稳定版本

2.0.1 2024年8月4日
2.0.0 2024年7月30日
1.7.2 2024年7月27日
1.6.3 2024年2月23日
1.3.0 2023年7月29日

#93 in 进程宏

Download history 1/week @ 2024-06-29 10/week @ 2024-07-06 97/week @ 2024-07-13 11/week @ 2024-07-20 320/week @ 2024-07-27 130/week @ 2024-08-03 8/week @ 2024-08-10

477 每月下载次数

MIT 许可证

83KB
1.5K SLoC

WarcRwLock

Crates.io License: MIT

安装

要使用WarcRwLock crate,请将以下依赖项添加到您的 Cargo.toml

[dependencies]
warcrwlock = "2.0.1"

描述

Warcrwlock是一个将简单数据结构转换为原子自引用的抽象,使您可以使用Arc和RwLock实现同时读写控制。在安全性方面,Rust设计的软件或部分实现具有显著优势,性能可媲美C++。因此,主要动机是通过抽象异步安全地共享数据的能力来提高这些应用程序的生产力。


Warcrwock结构属性

可以将简单的struct转换为两个结构。 "核心"是保留原始特性的部分,但被放置在名为 "核心" 的模块中。这样做的原因是允许它在不损害主结构的情况下与派生类型一起使用。请参见下面的示例

mod core{
    #[derive(Debug)]
    pub(super) struct MyStruct {
        pub(super) value: usize,
    }
}

使用相同的标识符创建另一个结构,该结构将包含一个字段,如下面的示例所示

struct MyStruct {
    core : Arc<RwLock<core::MyStruct>>,
}
//impls...

访问器

为了便于实现,需要使用访问器。访问器是为原始结构的每个字段自动生成的。使用上一个示例中的 MyStruct 并添加一个字段,我们将有4个生成的方法。

public_read_only 是一个必须用于字段的属性,以便将可变访问方法私有化。一个重要的细节是,访问器使用与字段相同的可见性类型生成,如下面的示例所示

    #[warcrwlock]
    pub struct MyStruct {
        pub value: usize,
        #[public_read_only]
        pub value_2 : usize,
        value_3 : usize
    }

结果...

    impl MyStruct {
        pub fn value(&self) -> MyStructRefLock<usize>{...}
        pub fn value_mut(&mut self) -> MyStructMutLock<usize>{...}
        pub fn value_2(&self) -> MyStructRefLock<usize>{...}
        fn value_2_mut(&mut self) -> MyStructMutLock<usize>{...}
        fn value_3(&self) -> MyStructRefLock<usize>{...}
        fn value_3_mut(&mut self) -> MyStructMutLock<usize>{...}
    }

构造函数

为了方便构建包装器,生成了一个私有的 builder 方法,该方法将接收所有值,让您有权按需实现自己的构造方法。

以下将根据前述示例进行演示。

    impl MyStruct {
        fn builder(value : usize, value : usize) -> Self{...}
    }

限制

  • 字段值只能通过方法访问。
  • 结构无法具有关联的 lifetime

Warcrwock 实现属性

用户通过访问器和构造器编写和读取结构的字段。问题是这可能在某些情况下变得繁琐且适应性差。因此,如果将 warcrwlock 属性也放置在实现中,就可以在不使用 accessorsconstructors 的情况下在原始上下文中编程。

限制

  • 方法不能有关联的 lifetime
  • 没有 warcrwlock 属性的实现中的方法是不可见的。
  • 不允许返回具有 Self 作为泛型的类型,除了 Vec<Self>

特质支持

要在您的特质中使用 #[warcrwlock] 宏,只需在特质声明之前添加该属性。以下是一个示例

没有可变方法的特质示例

#[warcrwlock]
pub trait MyTrait {
    fn method_with_ret(&self) -> i32;
}

用途

struct MyStructA(i32);

impl MyTrait for MyStructA {
    fn method_with_ret(&self) -> i32 {
        self.0
    }
}

struct MyStructB(i32);

impl MyTrait for MyStructB {
    fn method_with_ret(&self) -> i32 {
        self.0
    }
}

fn use_test() {
    fn sum(a: MyTraitAbstract, b: MyTraitAbstract) -> i32 {
        a.method_with_ret() + b.method_with_ret()
    }
    let sum = sum((&mut MyStructA(3)).into(), (&mut MyStructB(7)).into());
    assert_eq!(sum, 10);
}

没有可变方法的特质示例

#[warcrwlock]
pub trait MyTrait {
    fn method_with_ret(&self) -> i32;
    fn method_with_ret_mut(&mut self) -> &mut i32;
}
struct MyStructA(i32);

impl MyTrait for MyStructA {
    fn method_with_ret(&self) -> i32 {
        self.0
    }
    fn method_with_ret_mut(&mut self) -> &mut i32 {
        &mut self.0
    }
}
struct MyStructB(i32);

impl MyTrait for MyStructB {
    fn method_with_ret(&self) -> i32 {
        self.0
    }
    fn method_with_ret_mut(&mut self) -> &mut i32 {
        &mut self.0
    }
}

fn use_test() {
    let a = &mut MyStructA(5);
    let mut a: MyTraitAbstract = a.into();
    let b = &mut MyStructB(10);
    let mut b: MyTraitAbstract = b.into();
    assert_eq!(a.method_with_ret(), 5);
    assert_eq!(b.method_with_ret(), 10);
    *a.method_with_ret_mut() = 50;
    *b.method_with_ret_mut() = 100;
    assert_eq!(a.method_with_ret(), 50);
    assert_eq!(b.method_with_ret(), 100);
}

不安全克隆

这个 unsafe_clone 函数允许克隆 Abstract Forms 的实例,但由于可能共享可变引用,因此它是不安全的。

引用共享问题

当框架实现多个使用 #[warcrwlock] 的特质,并且其中一个特质有一个返回另一个“抽象形式”的方法时,可能会存在未保证的可变引用共享。这破坏了引用的唯一所有权的保证,可能导致竞态条件和未定义的行为。

因此,从版本 (2.0.0) 开始,通过用不安全克隆替换克隆实现来缓解了此所有权问题。

示例

mod trait_a {
    use warcrwlock::warcrwlock;
    #[warcrwlock]
    pub trait MyTraitA {
        fn number(&mut self) -> &mut f64;
    }
}
mod trait_b {
    use warcrwlock::warcrwlock;
    use super::MyTraitAAbstract;
    #[warcrwlock]
    pub trait MyTraitB {
        fn as_my_trait_a(&mut self) -> MyTraitAAbstract;
        fn number(&self) -> &f64;
    }
}

struct MyStruct(f64);

impl MyTraitA for MyStruct {
    fn number(&mut self) -> &mut f64 {
        &mut self.0
    }
}

impl MyTraitB for MyStruct {
    fn as_my_trait_a(&mut self) -> MyTraitAAbstract {
        self.into()
    }

    fn number(&self) -> &f64 {
        &self.0
    }
}

历史

  • 1.1.0:现在可以自由实现与展示的结构类型相同的参数的方法。
  • 1.2.0:添加了一个名为 wrapper_method 的属性,该属性进入框架的包装器“范围”。
  • 1.2.1:具有条件可见性或除公共和私有(如 pub(crate))之外的可见性的方法被当作公共方法处理。
  • 1.3.0:添加了一个新的属性,称为 visible_to_wrapper,以便私有方法可被包装器方法访问。
  • 1.4.0:包装器现在实现了 PartialEq。
  • 1.4.1:修复了与 derive 宏和其他宏的兼容性。
  • 1.4.2:修复了语法树中的固定属性和类型识别失败问题。
  • 1.5.0:重构和错误修复,移除了自版本 1.2.0 添加的不必要属性。
  • 1.5.2:修复了泛型支持。
  • 1.6.0:添加了 "public_read_only" 属性。
  • 1.6.1:修复了访问保护器的返回类型。
  • 1.6.2:修复了保护器的访问方法。
  • 1.6.3:修复了关于公共参数的保护器访问方法。
  • 1.7.1:添加了对特质的支持。
  • 1.7.2:修复了封装特质中的导入。
  • 2.0.0:出于安全原因,将特质的可变方法抽象形式的克隆实现替换为其自身的非安全克隆实现。
  • 2.0.1:修复了非安全克隆。

贡献

WarcRwLock 项目主要由一位名为 PFP 的开发者维护,但欢迎社区贡献。然而,贡献必须保持在项目主要功能的范围内。

许可证

本项目采用 MIT 许可证。有关更多详细信息,请参阅 LICENSE 文件。

依赖关系

~0.8–1.7MB
~33K SLoC