mut_set_derive

Crates.iomut_set_derive
lib.rsmut_set_derive
version0.5.0
sourcesrc
created_at2024-03-28 07:19:22.556386
updated_at2024-11-08 09:58:37.767489
descriptionA safe implementation for HashSet with iter_mut and get_mut
homepage
repositoryhttps://github.com/zao111222333/mut_set
max_upload_size
id1188813
size27,229
Junzhuo ZHOU (zao111222333)

documentation

https://docs.rs/mut_set

README

mut_set

License github crates.io Docs

Use the idea of readonly to implement HashSet with iter_mut and get_mut.

Add crates by following command

cargo add mut_set mut_set_derive

or add it into Cargo.toml

[dependencies]
mut_set = "0.3"
mut_set_derive = "0.3"

Demo

#[derive(Debug)]
#[mut_set_derive::item]
pub(super) struct MyItem<T1, T2>
where
    T1: Sized,
{
    #[id]
    pub id1: usize,
    pub ctx1: T1,
    pub(in crate::derive) ctx2: T2,
    #[id]
    pub id2: String,
}

#[test]
fn test() {
    let mut set = mut_set::MutSet::new();
    println!("{:?}", set);
    set.insert(MyItem {
        id1: 2,
        id2: "www".to_string(),
        ctx1: -1,
        ctx2: "ccc".to_string(),
    });
    set.insert(MyItem {
        id1: 1,
        id2: "ww".to_string(),
        ctx1: -2,
        ctx2: "cc".to_string(),
    });
    println!("{:?}", set);
    for v in set.iter() {
        println!("{:?}", v);
    }
    for v in set.iter_mut() {
        v.ctx1 = 0;
        println!("{:?}", v.id1);
        // In `iter_mut` IDs write will be prohibited
        // v.id1 = 0;
    }
    println!("{:?}", set);
    let id1 = MyItem::id(2, "www".to_string());
    println!("{:?}", set.get(&id1));
    for v in set.into_iter() {
        println!("{:?}", v);
    }
}

How does mut_set work

The macro will implement all stuffs in tests/src/basic_expand.rs.

Take Xxx as an example:

  • Create two struct ImmutIdXxx, and XxxId. Where ImmutIdXxx is same to Xxx with private id fields, and XxxId only contains id fields.
  • Do rearrangement so that all id fields are located at beginning of the structure. By the help of #[repr(C)], we can use raw pointer operations to (zero-cost?) convert Xxx, ImmutIdXxx, and XxxId.
  • impl mut_set::Item for Xxx<ImmutIdItem = ImmutIdXxx>
  • MutSet<T: Item> = HashMap<u64, T::ImmutIdItem>, where the u64 is the hash value.
  • Wrap the iteration function
    • iter(&self) -> Iter<&Xxx>
    • into_iter(self) -> Iter<Xxx>
    • iter_mut(&mut self) -> Iter<&mut ImmutIdXxx>

Other features

  • If you want to add some derive/proc_macro to ImmutIdXxx/XxxId. You can add arguments to mut_set_derive::item, to specify which derive should add to ImmutIdXxx/XxxId, and the filter for fileds attribute. e.g.,

    #[mut_set_derive::item(
    macro(derive(Debug, Clone);
          derive(derivative::Derivative);
          derivative(Default);),
    attr_filter(derivative;)
    )]
    struct Xxx {
        #[id]
        id: usize,
        #[derivative(Default(value = "8"))]
        #[some_attr]
        ctx: usize,
    }
    

    will impl

    #[derive(Debug, Clone)]
    #[derive(derivative::Derivative)]
    #[derivative(Default)]
    struct ImmutIdXxx {
        id: usize,
        #[derivative(Default(value = "8"))]
        ctx: usize,
    }
    
    #[derive(Debug, Clone)]
    #[derive(derivative::Derivative)]
    #[derivative(Default)]
    struct XxxId {
        id: usize,
    }
    

    Here some_attr is not in attr_filter(), so it will be removed. See more at tests/src/derive.rs and tests/src/derive_expand.rs.

Commit count: 48

cargo fmt