#vec #container #type-erasure #any #no-alloc #no-std #send-sync

no-std any_vec

类型擦除向量。大多数操作无需类型知识。几乎零开销。

17 个版本 (破坏性)

0.14.0 2024 年 5 月 10 日
0.13.0 2023 年 8 月 25 日
0.12.0 2023 年 6 月 10 日
0.11.0 2022 年 8 月 26 日
0.10.0 2022 年 7 月 10 日

#83 in 数据结构

Download history 2990/week @ 2024-04-26 3406/week @ 2024-05-03 3073/week @ 2024-05-10 2360/week @ 2024-05-17 2405/week @ 2024-05-24 2244/week @ 2024-05-31 2006/week @ 2024-06-07 3041/week @ 2024-06-14 2715/week @ 2024-06-21 2381/week @ 2024-06-28 3689/week @ 2024-07-05 3690/week @ 2024-07-12 2472/week @ 2024-07-19 3101/week @ 2024-07-26 2825/week @ 2024-08-02 1556/week @ 2024-08-09

10,392 每月下载量
用于 3 个 crate (2 直接)

MIT/Apache

130KB
2.5K SLoC

crates.io license Docs CI

类型擦除向量。所有元素具有相同类型。

设计为尽可能类型擦除 - 大多数操作不知道具体的类型。例如,您可以将一个类型擦除向量中的项移动或复制/克隆到另一个类型擦除向量中,而不必知道它们的类型。或者您可以在类型擦除向量内部擦除、交换、移动、复制元素等...

只有类型擦除的析构和克隆操作有间接调用的额外开销。

用法

    let mut vec: AnyVec = AnyVec::new::<String>();
    {
        // Typed operations.
        let mut vec = vec.downcast_mut::<String>().unwrap();
        vec.push(String::from("0"));
        vec.push(String::from("1"));
        vec.push(String::from("2"));
    }
 
    let mut other_vec: AnyVec = AnyVec::new::<String>();
    // Fully type erased element move from one vec to another
    // without intermediate mem-copies.
    let element = vec.swap_remove(0);
    other_vec.push(element);

    // Output 2 1
    for s in vec.downcast_ref::<String>().unwrap(){
        println!("{}", s);
    } 

有关更多信息,请参阅 文档

Send, Sync, Clone

您可以使得 AnyVec 具有可 Send、可 Sync 和可 Clone 的能力。

use any_vec::AnyVec;
use any_vec::traits::*;
let v1: AnyVec<dyn Cloneable + Sync + Send> = AnyVec::new::<String>();
let v2 = v1.clone();

这些约束将在编译时应用于元素类型

// This will fail to compile. 
let v1: AnyVec<dyn Sync + Send> = AnyVec::new::<Rc<usize>>();

不可克隆的 AnyVec 的大小比 1 个指针小。

LazyClone

尽可能情况下,any_vec 类型擦除的元素可以懒加载克隆。

 let mut v1: AnyVec<dyn Cloneable> = AnyVec::new::<String>();
 v1.push(AnyValueWrapper::new(String::from("0")));

 let mut v2: AnyVec<dyn Cloneable> = AnyVec::new::<String>();
 let e = v1.swap_remove(0);
 v2.push(e.lazy_clone());
 v2.push(e.lazy_clone());

MemBuilder

MemBuilder + Mem 对于 AnyVec 来说就像 Allocator。但与分配器不同,Mem 的容器专用设计允许进行更多优化。例如,通过更改 MemBuilder,可以从 AnyVec 创建堆分配的 FixedAnyVec 和小型缓冲区优化(SBO) SmallAnyVec

type FixedAnyVec<Traits = dyn None> = AnyVec<Traits, Stack<512>>;
let mut any_vec: FixedAnyVec = AnyVec::new::<String>();

// This will be on stack, without any allocations.
any_vec.push(AnyValueWrapper::new(String::from("0")))

借助 clone_empty_in,您可以使用堆分配或 SBO AnyVec 作为未知类型值的快速中间存储。

fn self_push_first_element<T: Trait + Cloneable>(any_vec: &mut AnyVec<T>){
    let mut tmp = any_vec.clone_empty_in(StackN::<1, 256>);
    tmp.push(any_vec.at(0).lazy_clone());
    any_vec.push(tmp.pop().unwrap());
}

MemBuilder 接口,作为有状态的接口,允许创建可以与复杂自定义分配器一起工作的 Mem

no_std + no_alloc

这是一个 no_std 库,也可以在没有 alloc 的情况下工作。

变更日志

有关版本差异,请参阅 CHANGELOG.md

已知替代方案

  • type_erased_vec。允许以类型擦除的方式存储 Vec<T>,但你需要执行操作时,需要先“转换”为具体类型。
  • untyped_vec。一些操作(如 lencapacity)无需类型知识即可执行;但其余操作则需要具体类型。

无运行时依赖