An efficient alternative to dyn Trait
for containerized types.
This crate aims to fill the gap in Rust's dynamic traits system by exposing the control over dynamic virtual function tables to the user in a safe API. This library is in prototype stage and is not recommended for production use.
Currently only untyped Vec
s and Slice
s are implemented. Complementary Value
types
are provided for compatibility with traditional, typed containers like VecDeque
s and HashMap
s.
Notably dync
introduces the following types:
VecCopy<V>
- a homogeneous collection ofCopy
types generic over the virtual function table,VecDyn<V>
- a homogeneous collection generic over the virtual function table,SliceCopy<V>
(andSliceCopyMut<V>
) - a homogeneous slice (and mutable slice) ofCopy
types generic over the virtual function table,Slice<V>
(andSliceMut<V>
) - a homogeneous slice (and mutable slice) of types generic over the virtual function table,BoxValue<V>
- an untyped boxed value of any size.SmallValue<V>
- an untyped value that fits into ausize
.ValueRef<V>
(andValueMut<V>
) - an untyped value reference (and mutable reference).CopyValueRef<V>
(andCopyValueMut<V>
) - an untyped value reference (and mutable reference) of aCopy
type.
The main difference between the Copy
variants of these is that they do not require a designated
drop function pointer, which makes them simpler and potentially more performant. However, the
benchmarks have not revealed any performance advantages in the Copy
variants, so it is recommended
to always use the fully dynamic variants (e.g. VecDyn
instead of VecCopy
and Slice
instead of
SliceCopy
) by default. Furthermore the Copy
variants may be deprecated in the future to simplify
the API.
Create homogeneous untyped Vec
s that store a single virtual function table for all contained
elements:
use dync::VecDrop; // VecDyn<DropVTable>
// Create an untyped `Vec`.
let vec: VecDrop = vec![1_i32,2,3,4].into();
// Access elements either by downcasting to the underlying type.
for value_ref in vec.iter() {
let int = value_ref.downcast::<i32>().unwrap();
println!("{}", int);
}
// Or downcast the iterator directly for more efficient traversal.
for int in vec.iter_as::<i32>().unwrap() {
println!("{}", int);
}
The VecDrop
type above defaults to the empty virtual table (with the exception of the drop
function), which is not terribly useful when the contained values need to be processed in
some way. dync
provides support for common standard library traits such as:
Drop
Clone
PartialEq
std::hash::Hash
std::fmt::Debug
Send
andSync
- more to come
So to produce a VecDyn
of a printable type, we could instead do
use dync::{VecDyn, traits::DebugVTable};
// Create an untyped `Vec` of `std::fmt::Debug` types.
let vec: VecDyn<DebugVTable> = vec![1_i32,2,3,4].into();
// We can now iterate and print value references (which inherit the VTable from the container)
// without needing a downcast.
for value_ref in vec.iter() {
println!("{:?}", value_ref);
}
See the exmaples
directory for more.
This library does not include serialization/deserialization functionality for the provided types since these would need
to handle serializing/deserializing functions in the virtual table, which is out of the scope of this library. For
serialization/desrialization it is recommended to simply convert untyped collections to typed collections
(e.g. VecDrop -> Vec<T>
).
This repository is licensed under either of
- Apache License, Version 2.0, (LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0)
- MIT License (LICENSE-MIT or https://opensource.org/licenses/MIT)
at your option.