[![crates.io](https://img.shields.io/crates/v/any_vec.svg)](https://crates.io/crates/any_vec) [![license](https://img.shields.io/badge/license-Apache--2.0_OR_MIT-blue?style=flat-square)](#license) [![Docs](https://docs.rs/any_vec/badge.svg)](https://docs.rs/any_vec) [![CI](https://github.com/tower120/any_vec/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/tower120/any_vec/actions/workflows/ci.yml) Type erased vector. All elements have the same type. Designed to be type-erased as far as possible - most operations do not know a concrete type. For example, you can move or copy/clone items from one type-erased vector to another, without ever knowing their type. Or you can erase, swap, move, copy elements inside type-erased vector, etc... Only type-erased destruct and clone operations have additional overhead of indirect call. # Usage ```rust let mut vec: AnyVec = AnyVec::new::(); { // Typed operations. let mut vec = vec.downcast_mut::().unwrap(); vec.push(String::from("0")); vec.push(String::from("1")); vec.push(String::from("2")); } let mut other_vec: AnyVec = AnyVec::new::(); // 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::().unwrap(){ println!("{}", s); } ``` See [documentation](https://docs.rs/any_vec) for more. ## Send, Sync, Clone You can make `AnyVec` `Send`able, `Sync`able, `Clone`able: ```rust use any_vec::AnyVec; use any_vec::traits::*; let v1: AnyVec = AnyVec::new::(); let v2 = v1.clone(); ``` This constraints will be applied compiletime to element type: ```rust // This will fail to compile. let v1: AnyVec = AnyVec::new::>(); ``` Non-Clonable `AnyVec` has a size 1 pointer smaller. ## LazyClone Whenever possible, `any_vec` type erased elements can be lazily cloned: ```rust let mut v1: AnyVec = AnyVec::new::(); v1.push(AnyValueWrapper::new(String::from("0"))); let mut v2: AnyVec = AnyVec::new::(); let e = v1.swap_remove(0); v2.push(e.lazy_clone()); v2.push(e.lazy_clone()); ``` ## MemBuilder `MemBuilder` + `Mem` works like `Allocator` for `AnyVec`. But unlike allocator, `Mem` container-specialized design allows to perform more optimizations. For example, it is possible to make stack-allocated `FixedAnyVec` and small-buffer-optimized(SBO) `SmallAnyVec` from `AnyVec` by just changing `MemBuilder`: ```rust type FixedAnyVec = AnyVec>; let mut any_vec: FixedAnyVec = AnyVec::new::(); // This will be on stack, without any allocations. any_vec.push(AnyValueWrapper::new(String::from("0"))) ``` With help of `clone_empty_in` you can use stack allocated, or SBO `AnyVec` as fast intermediate storage for values of unknown type: ```rust fn self_push_first_element(any_vec: &mut AnyVec){ 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` interface, being stateful, allow to make `Mem`, which can work with complex custom allocators. ## no_std + no_alloc This is `no_std` library, which can work without `alloc` too. ### Changelog See [CHANGELOG.md](CHANGELOG.md) for version differences. # Known alternatives * [type_erased_vec](https://crates.io/crates/type_erased_vec). Allow to store `Vec` in type erased way, but you need to perform operations, you need to "cast" to concrete type first. * [untyped_vec](https://crates.io/crates/untyped_vec). Some operations like `len`, `capacity` performed without type knowledge; but the rest - require concrete type.