Amplifying Rust language capabilities: multiple generic trait implementations,
type wrappers, derive macros. Tiny library with zero non-optional dependencies.
Able to work as no_std
.
Minimum supported rust compiler version (MSRV): 1.66.0; rust edition 2021.
Library proposes generic implementation strategies, which allow multiple generic trait implementations.
Implementing trait for a generic type ("blanket implementation") more than once
(applies both for local and foreign traits) - or implement foreign trait for a
concrete type where there is some blanket implementation in the upstream. The
solution is to use special pattern by @Kixunil. I use it widely and have a
special helper type in src/strategy.rs
src/strategy.rs module.
With that helper type you can write the following code, which will provide you
with efficiently multiple blanket implementations of some trait SampleTrait
:
pub trait SampleTrait {
fn sample_trait_method(&self);
}
// Define strategies, one per specific implementation that you need,
// either blanket or concrete
pub struct StrategyA;
pub struct StrategyB;
pub struct StrategyC;
// Define a single marker type
pub trait Strategy {
type Strategy;
}
// Do a single blanket implementation using Holder and Strategy marker trait
impl<T> SampleTrait for T
where
T: Strategy + Clone,
amplify::Holder<T, <T as Strategy>::Strategy>: SampleTrait,
{
// Do this for each of sample trait methods:
fn sample_trait_method(&self) {
amplify::Holder::new(self.clone()).sample_trait_method()
}
}
// Do this type of implementation for each of the strategies
impl<T> SampleTrait for amplify::Holder<T, StrategyA>
where
T: Strategy,
{
fn sample_trait_method(&self) {
/* ... write your implementation-specific code here */
}
}
# pub struct ConcreteTypeA;
// Finally, apply specific implementation strategy to a concrete type
// (or do it in a blanket generic way) as a marker:
impl Strategy for ConcreteTypeA {
type Strategy = StrategyA;
}
- Display
- From
- Error
- Getters
- AsAny
- Wrapper
A sample of what can be done with the macros:
#[derive(From, Error, Display, Debug)]
#[display(doc_comments)]
pub enum Error {
// You can specify multiple conversions with separate attributes
#[from(::std::io::Error)]
#[from(IoError)]
/// Generic I/O error
Io,
#[from]
// This produces error description referencing debug representation
// of the internal error type
/// Formatting error: {_0:}
Format(::std::fmt::Error),
#[from]
/// Some complex error, here are details: {details}
WithFields { details: ::std::str::Utf8Error },
#[display(LowerHex)]
MultipleFields {
// ...and you can also covert error type
#[from(IoErrorUnit)]
// rest of parameters must implement `Default`
io: IoError,
#[display(ToHex::to_hex)]
details: String,
},
}
More information is given in amplify_derive
crate README.
none!
as an alias forDefault::default()
on collection types and types for which semantics makes it sensible to emphasize that the operation initializes empty structure.s!
for fast&str
->String
conversions- Collection-generating macros:
map!
&bmap!
for a rappidHashMap
andBTreeMap
creationset!
&bset!
for a rappidHashSet
andBTreeSet
creationlist!
forLinkedList
Wrapper trait helps in creating wrapped rust newtypes, Wrapped types are used for allowing implemeting foreign traits to foreign types: https://doc.rust-lang.org/stable/rust-by-example/generics/new_types.html
Trait defines convenient methods for accessing inner data, construct and deconstruct newtype. It also serves as a marker trait for newtypes.
The trait works well with #[derive(Wrapper)]
from amplify_derive
crate
cargo build --all
cargo test
As a reminder, minimum supported rust compiler version (MSRV) is 1.36.0, so it
can be build with either nightly, dev, stable or 1.36+ version of the rust
compiler. Use rustup
for getting the proper version, or add +toolchain
parameter to both cargo build
and cargo test
commands.
RUSTFLAGS="--cfg bench" cargo bench