Amplifying Rust language capabilities: multiple generic trait implementations, type wrappers, derive macros.
This is a part of Rust language amplification library providing required derive macros.
Minimum supported rust compiler version (MSRV): 1.60.0. Rust edition 2021.
- Generate [
Display
] descriptions using other formatting trait:#[derive(Display, Debug)] #[display(Debug)] struct Some { /* ... */ }
- Use existing function for displaying descriptions:
Formatting function must return [
#[derive(Display)] #[display(Int::print)] union Int { uint: u32, int: i32 }; impl Int { pub fn print(&self) -> String { s!("Integer representation") } }
String
] and take a singleself
argument (if you need formatting with streamed output, use one of existing formatting traits as shown in pt. 1). - Custom format string:
#[derive(Display)] #[display("({x}, {y})")] struct Point { x: u32, y: u32 }
- Use of doc comments for descrition representation. In this case doc
comments may also contain formatting like in the case 3:
You can also mix in this mode with other fors of display tags on a specific options; in this case doc comments are ignored
#[macro_use] extern crate amplify; #[derive(Display)] #[display(doc_comments)] enum Variants { /// Letter A A, /// Letter B B, /// This comment is ignored #[display("Letter C")] C, /// Letter {_0} Letter(String) }; assert_eq!(format!("{}", Variants::C), "Letter C"); assert_eq!(format!("{}", Variants::Letter(s!("K"))), " Letter K");
Advanced use with enums:
#[derive(Debug, Display)]
#[display(Debug)]
enum Test {
Some,
#[display = "OtherName"]
Other,
Named {
x: u8,
},
#[display = "Custom{x}"]
NamedCustom {
x: u8,
},
Unnamed(u16),
// NB: Use `_`-prefixed indexes for tuple values
#[display = "Custom{_0}"]
UnnamedCustom(String),
}
Error derive macro works to the full extend only when other derive macros
are used. With #[derive(Display)]
and [display(doc_comments)]
it uses
doc comments for generating error descriptions; with #[derive(From)]
it
may automatically implement transofrations from other error types.
#[derive(Debug, Display, Error)]
#[display(doc_comments)]
enum Error {
/// I/O operation error
Io,
/// Math overflow
Overflow,
/// Zero division with {_0}
ZeroDivision(u16),
}
Implements [From
] trait for the whole entity and/or its separate fields.
Works well with #[derive(Error)]
and, in many cases may require
[Default
] implementation (for details, pls see Examples below)
#[derive(From, Default)]
#[from(::std::io::Error)]
// Structure may contain no parameters
pub struct IoErrorUnit;
#[derive(From, Default)]
#[from(::std::io::Error)] // When no explicit binding is given, structure must implement `Default`
pub struct IoError {
details: String,
#[from]
kind: IoErrorUnit,
}
#[derive(From)]
pub enum Error {
// You can specify multiple conversions with separate attributes
#[from(::std::io::Error)]
#[from(IoError)]
Io,
#[from]
Format(::std::fmt::Error),
#[from]
WithFields { details: ::std::str::Utf8Error },
MultipleFields {
// ...and you can also covert error type
#[from(IoErrorUnit)]
// rest of parameters must implement `Default`
io: IoError,
details: String,
},
}
#[derive(From)]
pub struct Wrapper(u32, i16);
Creates rust new type wrapping existing type. Can be used in sturctures
containing multiple named or unnamed fields; in this case the field you'd
like to wrap should be marked with #[wrap]
attribute; otherwise the first
field is assumed to be the wrapped one.
Use with multiple fileds requires that you do From
and Default
derive
on the main structure.
Supports automatic implementation of the following traits:
amplify::Wrapper
AsRef
AsMut
Borrow
BorrowMut
Deref
DerefMut
Complete usage of this derive macro is possible only with nightly rust
compiler with trivial_bounds
feature gate set for the crate and nightly
feature set. This will give you an automatic implementation for additional
traits, it they are implemented for the wrapped type:
Display
LowerHex
UpperHex
LowerExp
UpperExp
Octal
Index
IndexMut
Add
AddAssign
Sub
SubAssign
Mul
MulAssign
Div
DivAssign
Other traits, such as PartialEq
, Eq
, PartialOrd
, Ord
,
Hash
can be implemented using standard #[derive]
attribute in the
same manner as Default
, Debug
and From
use std::marker::PhantomData;
use amplify::Wrapper;
#[derive(Clone, Wrapper, Default, From, Debug)]
struct Wrapped<T, U>(
#[wrap]
#[from]
HashMap<usize, Vec<U>>,
PhantomData<T>,
)
where
U: Sized + Clone;
let w = Wrapped::<(), u8>::default();
assert_eq!(w.into_inner(), HashMap::<usize, Vec<u8>>::default());
Creates getter methods matching field names for all fields within a structure (including public and private fields). Getters return reference types.
#[derive(Getters, Default)]
struct One {
a: Vec<u8>,
pub b: bool,
pub(self) c: u8,
}
let one = One::default();
assert_eq!(one.a(), &Vec::<u8>::default());
assert_eq!(one.b(), &bool::default());
assert_eq!(one.c(), &u8::default());
Trait [amplify::AsAny
] allows simple conversion of any type into a generic
"thick" pointer &dyn Any
(see [::core::any::Any
]), that can be later
converted back to the original type with a graceful failing for all other
conversions. AsAny
derive macro allows to implement this trait for
arbitrary time without much hussle:
# #[macro_use] extern crate amplify_derive;
extern crate amplify;
use amplify::AsAny;
#[derive(AsAny, Copy, Clone, PartialEq, Eq, Debug)]
struct Point {
pub x: u64,
pub y: u64,
}
#[derive(AsAny, PartialEq, Debug)]
struct Circle {
pub radius: f64,
pub center: Point,
}
let mut point = Point { x: 1, y: 2 };
let point_ptr = point.as_any();
let mut circle = Circle {
radius: 18.,
center: point,
};
let circle_ptr = circle.as_any();
assert_eq!(point_ptr.downcast_ref(), Some(&point));
assert_eq!(circle_ptr.downcast_ref(), Some(&circle));
assert_eq!(circle_ptr.downcast_ref::<Point>(), None);
let p = point_ptr.downcast_ref::<Point>().unwrap();
assert_eq!(p.x, 1)