#map #deterministic #certainty #metainfo

certain-map-macros

一种确保元素存在的类型化映射

5 个版本

0.2.3 2023年6月29日
0.2.2 2023年6月26日
0.2.1 2023年6月25日
0.2.0 2023年6月25日
0.1.0 2023年6月21日

#deterministic 中排名第 65

Download history 15/week @ 2024-03-11 30/week @ 2024-03-18 76/week @ 2024-03-25 84/week @ 2024-04-01 32/week @ 2024-04-08 5/week @ 2024-04-15 3/week @ 2024-04-22 28/week @ 2024-04-29 4/week @ 2024-05-13 49/week @ 2024-05-20 46/week @ 2024-05-27 37/week @ 2024-06-03 1/week @ 2024-06-10 8/week @ 2024-06-17 47/week @ 2024-06-24

每月下载量 94
用于 certain-map

MIT/Apache

25KB
481

特定映射

Crates.io

一种确保元素存在的类型化映射。

解决的问题

在 Rust 中,我们经常使用服务抽象进行模块化结构设计(例如 tower-serviceservice-async)。

服务是堆叠的,不同层的请求/响应类型可能不同。

当不同层的组件存在数据依赖关系时,尤其是间接依赖关系,通过更改请求/响应类型来传递所有所需信息变得很困难。

当需要传递的变量数量增加或减少时,我们必须重新定义一个结构来加载这些数量,并且需要为这些结构实现转换函数和数据提取函数。这将是一项巨大而枯燥的工作,并且会使代码变得杂乱。

因此,我们通常不这样做,我们经常使用 HashMap 或 TypeMap 来管理需要在服务之间传递的信息。

但这将带来一个明显的问题:我们无法在编译时确保在读取时所需的键值已经被设置。这可能导致我们程序中的不合理错误处理分支或在某些场景中发生 panic。

优点

在这个crate中,我们在插入或删除键时转换结构类型。因此,我们可以确保某些值在编译时必须存在。

当您需要使用结构在多个阶段之间传递信息时,这个crate将非常适合您。

这再次实现了承诺:如果编译成功,则它将工作。

使用方法

use certain_map::{certain_map, Param, ParamRef, ParamRemove, ParamSet, ParamTake};

struct UserName(String);

#[derive(Copy, Clone)]
struct UserAge(u8);

certain_map! {
    pub struct MyCertainMap {
        name: UserName,
        #[ensure(Clone)]
        age: UserAge,
    }
}

fn main() {
    let meta = MyCertainMap::new();

    // The following line compiles fail since there's no UserName in the map.
    // log_username(&meta);

    let meta = meta.param_set(UserName("ihciah".to_string()));
    // Now we can get it with certainty.
    log_username(&meta);

    let (meta, removed) = ParamTake::<UserName>::param_take(meta);
    assert_eq!(removed.0, "ihciah");
    // The following line compiles fail since the UserName is removed.
    // log_username(&meta);

    // We can also remove a type no matter if it exist.
    let meta = ParamRemove::<UserName>::param_remove(meta);

    let meta = meta.param_set(UserAge(24));
    // we can get ownership of fields with #[ensure(Clone)]
    log_age(&meta);
}

fn log_username<T: ParamRef<UserName>>(meta: &T) {
    println!("username: {}", meta.param_ref().0);
}

fn log_age<T: Param<UserAge>>(meta: &T) {
    println!("user age: {}", meta.param().0);
}

依赖

~290–750KB
~18K SLoC