created_at2020-06-13 01:41:55.058444
updated_at2024-02-15 23:04:06.190636
descriptionAmplifying Rust language capabilities: multiple generic trait implementations, type wrappers, derive macros
Dr. Maxim Orlovsky (dr-orlovsky)



# Rust Amplify Library ![Build]( ![Tests]( ![Lints]( [![codecov](]( [![](]( [![Docs](]( [![unsafe forbidden](]( [![MIT licensed](](./LICENSE) 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. ## Main features ### Generics 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/`]()src/ module. With that helper type you can write the following code, which will provide you with efficiently multiple blanket implementations of some trait `SampleTrait`: ```rust 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 SampleTrait for T where T: Strategy + Clone, amplify::Holder::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 SampleTrait for amplify::Holder 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; } ``` ### Derive macros - Display - From - Error - Getters - AsAny - Wrapper A sample of what can be done with the macros: ```rust #[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](derive/ ### Macros - `none!` as an alias for `Default::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 rappid `HashMap` and `BTreeMap` creation - `set!` & `bset!` for a rappid `HashSet` and `BTreeSet` creation - `list!` for `LinkedList` ### Wapper type Wrapper trait helps in creating wrapped rust *newtypes*, Wrapped types are used for allowing implemeting foreign traits to foreign types: 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 ## Build ```shell script 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. ## Benchmark ```shell RUSTFLAGS="--cfg bench" cargo bench ```
Commit count: 679

cargo fmt