11次发布

0.10.0 2022年10月21日
0.9.20 2022年5月16日
0.9.19 2022年1月3日
0.9.17 2021年11月21日
0.9.2 2019年3月4日

#1690数据结构

Download history 1/week @ 2024-04-06 1/week @ 2024-05-25 12/week @ 2024-06-08 2/week @ 2024-06-15 33/week @ 2024-06-29 45/week @ 2024-07-20

每月 78 次下载
用于 ecore_rs

MIT 协议

43KB
755

crates.io Documentation CI

safe_index

无成本的封装 usize 以赋予它们特定的类型。动机是拥有不同类型的索引,它们在类型级别上不兼容,从而降低了与使用 usize 相比混淆的机会。

通过宏创建索引类型,因此实际的类型属于客户端crate。这使用户能够用方法、特质实现等增强索引类型。

有关详细信息,请参阅文档

如果您在升级到版本 < 0.9.17 时遇到问题,请确保您已阅读变更日志


lib.rs:

强类型、零成本的整型索引封装。

此crate只是一个宏:new。它创建了一个封装在 usize 中的包装器,以创建类型安全的索引。也就是说,您用于从客户端信息向量中高效检索信息的索引与您关于客户端的文件索引类型不同。以下示例说明了此crate在该上下文中的应用。

创建的索引类型实现了

  • DerefFrom for usize,
  • DebugDefaultCloneCopyPartialOrdOrdPartialEqEqHashDisplay

如果您在升级到版本 < 0.9.17 时遇到问题,请确保您已阅读变更日志

用法

《new》的最基本用法就是封装某个对象

safe_index::new!{
    /// Arity.
    Arity
}
assert_eq! { core::mem::size_of::<Arity>(), core::mem::size_of::<usize>() }

然而,这并不很有用,因为索引没有可以索引的内容。幸运的是,《new》可以提供更多类型。在为索引类型强制性的标识符《Idx》之后,你可以添加这些

  • map <Map>:创建一个以《Idx》为索引的名为《<Map>`》的包装器,包装在向量上。
  • btree set <Set>:用于《Idx》的二叉树集合的别名类型。
  • btree map <Map>:从《Idx》到某物的二叉树映射的别名类型。

请参阅examples模块和下面的示例,以了解《new》宏的用法。

示例

此示例的所有代码都在examples::clients中。假设我们有一个存储在向量中的《Data》结构,其中包含一些客户信息。它还存储有关这些客户的文件。一个客户可以与多个文件相关联,一个文件也可以涉及多个客户。让我们通过索引来处理所有这些。

/// Client information.
pub struct ClientInfo {
    /// Name of the client.
    pub name: String,
    /// Indices of files associated with the client.
    pub files: BTreeSet<usize>,
}
/// File information.
pub struct FileInfo {
    /// Name of the file.
    pub name: String,
    /// Indices of clients concerned by the file.
    pub clients: BTreeSet<usize>,
}

/// Aggregates clients and files info.
pub struct Data {
    /// Map from client indexes to client information.
    pub clients: Vec<ClientInfo>,
    /// Map from file indexes to file information.
    pub files: Vec<FileInfo>,
}

现在,实现《Data》的功能可能会很痛苦。客户和文件索引都是《usize》,肯定会发生可怕的事情。

因此,让我们为每个创建一个索引类型。

/// Indices.
pub mod idx {
    safe_index::new! {
        /// Indices of clients.
        Client,
        /// Map from clients to something (really a vector).
        map: Clients,
        /// Set of clients.
        btree set: ClientSet,
    }

    safe_index::new! {
        /// Indices of files.
        File,
        /// Map from files to something (really a vector).
        map: Files,
        /// Set of files.
        btree set: FileSet,
    }
}

use idx::*;

/// Client information.
pub struct ClientInfo {
    /// Name of the client.
    pub name: String,
    /// Indices of files associated with the client.
    pub files: ClientSet,
}
/// File information.
pub struct FileInfo {
    /// Name of the file.
    pub name: String,
    /// Indices of clients concerned by the file.
    pub clients: FileSet,
}

/// Aggregates clients and files info.
pub struct Data {
    /// Map from client indexes to client information.
    pub clients: Clients<ClientInfo>,
    /// Map from file indexes to file information.
    pub files: Files<FileInfo>,
}

完整代码可在此处找到,您可以在examples::clients的文档中看到它被使用。以下是一些关于《Data》的函数,希望能展示《Client》和《File》如何(实际上就是)作为《usize》索引行为。

/// Aggregates clients and files info.
pub struct Data {
    /// Map from client indexes to client information.
    pub clients: Clients<ClientInfo>,
    /// Map from file indexes to file information.
    pub files: Files<FileInfo>,
}
impl Data {
    /// Adds a file, updates the clients concerned.
    pub fn add_file(&mut self, file: FileInfo) -> File {
        let idx = self.files.push(file);
        let file = &self.files[idx];
        for client in &file.clients {
            let is_new = self.clients[*client].files.insert(idx);
            debug_assert! { is_new }
        }
        idx
    }

    /// Adds a client to a file.
    pub fn add_client_to_file(&mut self, client: Client, file: File) {
        let is_new = self.files[file].clients.insert(client);
        debug_assert! { is_new }
        let is_new = self.clients[client].files.insert(file);
        debug_assert! { is_new }
    }
}

无运行时依赖项

功能