macro_rules! wrapper {
($($tt:tt)*) => { ... };
}Expand description
Helper macro for building a wrapper type and implementing common traits for it.
§Basic usage
Write the wrapper type definition using standard struct syntax, then add
#[wrapper(...)] attributes to automatically generate trait implementations
for interoperability with the inner type:
wrapper_lite::wrapper!(
#[wrapper(AsRef)]
#[derive(Debug, Clone, Copy)]
pub struct Foobar([u8; 128]);
);
wrapper_lite::wrapper!(
#[wrapper(AsRef)]
#[derive(Debug, Clone, Copy)]
pub struct Barfoo {
inner: [u8; 128],
}
);This macro supports both tuple struct syntax and braced struct syntax. When using the braced struct syntax, the first field will be treated as the “inner” field.
§Associated constructor method: from_inner
This macro will generate a const associated constructor method from_inner
when applicable, which takes an instance of the inner type and returns an
instance of the wrapper struct. The method will have the same visibility as
the inner field.
mod inner {
wrapper_lite::wrapper!(
pub(crate) struct Foobar<'a>(&'a str);
);
}
const _: () = {
let _ = inner::FooBar::from_inner("Hello");
};mod inner {
wrapper_lite::wrapper!(
pub(crate) struct Foobar<'a>(pub(crate) &'a str);
);
}
const _: () = {
let _ = inner::Foobar::from_inner("Hello");
};§The #[default(...)] attribute
When there are other fields in the wrapper struct, it is not possible to
construct an instance of the wrapper struct from the inner type alone. The
#[default(...)] attribute allows specifying default values for those
other fields to work around this limitation.
wrapper_lite::wrapper!(
struct Foobar {
inner_field: &'static str,
other_field: u8,
}
);
const _: () = {
let _ = Foobar::from_inner("Hello");
};wrapper_lite::wrapper!(
struct Foobar {
inner_field: &'static str,
#[default(0)]
other_field: u8,
}
);
const _: () = {
let foobar = Foobar::from_inner("Hello");
assert!(foobar.other_field == 0);
};Both the from_inner method and the From trait implementation
benefit from this.
§The #[wrapper(...)] attribute
Instructs the macro to automatically generate implementations of commonly used traits for the wrapper struct.
§#[wrapper(Debug)]
Implements trait Debug for the wrapper struct if the inner type
implements it.
wrapper_lite::wrapper!(
#[wrapper(Debug)]
struct Wrapper<'a>(&'a str);
);
assert_eq!(format!("{:?}", Wrapper { inner: "168" }), "\"168\"");§#[wrapper(DebugName)]
Implements trait Debug for the wrapper struct, but only prints the name
of the wrapper struct.
wrapper_lite::wrapper!(
#[wrapper(DebugName)]
struct Wrapper<'a>(&'a str);
);
assert_eq!(format!("{:?}", Wrapper { inner: "168" }), "Wrapper");§#[wrapper(Display)]
Implements trait Display for the wrapper struct if the inner type
implements it.
wrapper_lite::wrapper!(
#[wrapper(Display)]
struct Wrapper<'a>(&'a str);
);
assert_eq!(format!("{}", Wrapper { inner: "168" }), "168");§#[wrapper(AsRef)] / #[wrapper(AsMut)] / #[wrapper(Borrow)] / #[wrapper(BorrowMut)] / #[wrapper(Deref)] / #[wrapper(DerefMut)]
Implements trait AsRef / AsMut / Borrow / BorrowMut /
Deref / DerefMut for the wrapper struct.
The target type can be either the inner type or a custom type, provided that the inner type coerces to the target via deref coercion.
wrapper_lite::wrapper!(
#[wrapper(AsRef)]
#[wrapper(AsRef<[u8]>)]
struct Wrapper([u8; 42]);
);
const fn assert_as_ref<T, U>()
where
T: AsRef<U>,
U: ?Sized,
{
}
assert_as_ref::<Wrapper, [u8; 42]>();
assert_as_ref::<Wrapper, [u8]>();wrapper_lite::wrapper!(
#[wrapper(AsMut)]
#[wrapper(AsMut<[u8]>)]
struct Wrapper([u8; 42]);
);
const fn assert_as_mut<T, U>()
where
T: AsMut<U>,
U: ?Sized,
{
}
assert_as_mut::<Wrapper, [u8; 42]>();
assert_as_mut::<Wrapper, [u8]>();use core::borrow::Borrow;
wrapper_lite::wrapper!(
#[wrapper(Borrow)]
#[wrapper(Borrow<[u8]>)]
struct Wrapper([u8; 42]);
);
const fn assert_borrow<T, U>()
where
T: Borrow<U>,
U: ?Sized,
{
}
assert_borrow::<Wrapper, [u8; 42]>();
assert_borrow::<Wrapper, [u8]>();use core::borrow::{Borrow, BorrowMut};
wrapper_lite::wrapper!(
#[wrapper(BorrowMut)]
#[wrapper(BorrowMut<[u8]>)]
struct Wrapper([u8; 42]);
);
const fn assert_borrow<T, U>()
where
T: Borrow<U>,
U: ?Sized,
{
}
const fn assert_borrow_mut<T, U>()
where
T: BorrowMut<U>,
U: ?Sized,
{
}
assert_borrow::<Wrapper, [u8; 42]>();
assert_borrow_mut::<Wrapper, [u8; 42]>();
assert_borrow::<Wrapper, [u8]>();
assert_borrow_mut::<Wrapper, [u8]>();use core::ops::Deref;
wrapper_lite::wrapper!(
#[wrapper(Deref)]
struct WrapperA([u8; 42]);
);
wrapper_lite::wrapper!(
#[wrapper(Deref<[u8]>)]
struct WrapperB([u8; 42]);
);
const fn assert_deref<T, U>()
where
T: Deref<Target = U>,
U: ?Sized,
{
}
assert_deref::<WrapperA, [u8; 42]>();
assert_deref::<WrapperB, [u8]>();use core::ops::{Deref, DerefMut};
wrapper_lite::wrapper!(
#[wrapper(DerefMut)]
struct WrapperA([u8; 42]);
);
wrapper_lite::wrapper!(
#[wrapper(DerefMut<[u8]>)]
struct WrapperB([u8; 42]);
);
const fn assert_deref<T, U>()
where
T: Deref<Target = U>,
U: ?Sized,
{
}
const fn assert_deref_mut<T, U>()
where
T: DerefMut<Target = U>,
U: ?Sized,
{
}
assert_deref::<WrapperA, [u8; 42]>();
assert_deref_mut::<WrapperA, [u8; 42]>();
assert_deref::<WrapperB, [u8]>();
assert_deref_mut::<WrapperB, [u8]>();When #[wrapper(AsRef)] or #[wrapper(AsMut)] is specified, we will also
generate associated method as_inner or as_inner_mut that returns a
(mutable) reference to the inner value. These methods will have the same
visibility as the wrapper struct. Additionally, since mutable references are
not allowed in constant functions before Rust 1.83, and this library’s MSRV
is 1.56, by default the associated method as_inner_mut we generate is not
a const method, but we support the #[wrapper([const] AsMut)] syntax to
make as_inner_mut a const method like as_inner as well.
wrapper_lite::wrapper!(
#[wrapper([const] AsMut)]
pub struct Wrapper<P>(pub(crate) P);
);
const fn test_const_as_inner_mut<P>(wrapper: &mut Wrapper<P>) {
let _ = wrapper.as_inner_mut();
}When #[wrapper(BorrowMut)] or #[wrapper(DerefMut)] is specified, the
corresponding Borrow or Deref implementation is generated
automatically. Combining them with an explicit #[wrapper(Borrow)] or
#[wrapper(Deref)] therefore results in a duplicate implementation error:
wrapper_lite::wrapper!(
#[wrapper(Borrow)]
#[wrapper(BorrowMut)]
pub struct Wrapper<P>(pub(crate) P);
);wrapper_lite::wrapper!(
#[wrapper(Deref)]
#[wrapper(DerefMut)]
pub struct Wrapper<P>(pub(crate) P);
);§#[wrapper(From)]
Implements trait From for the wrapper struct, allowing it to be
constructed from the inner type. A const associated constructor method
with the same name from will also be generated.
wrapper_lite::wrapper!(
#[wrapper(From)]
pub struct Wrapper<P>(pub(crate) P);
);
const fn assert_from<T, U>()
where
T: From<U>,
{
}
const _: () = {
assert_from::<Wrapper<()>, ()>();
// This actually tests the generated `from` method.
let _ = Wrapper::from("Hello");
};§Advanced usage
§#[repr(align(cache))]
You can use #[repr(align(cache))] to pad and align the wrapper type to the
length of a cache line. This is useful for performance optimization in
certain scenarios.
use core::mem::align_of;
wrapper_lite::wrapper!(
#[repr(align(cache))]
pub struct Foobar(u8);
);
#[cfg(target_arch = "x86_64")]
const _: () = {
assert!(align_of::<Foobar>() == 128);
};§Notes
§wrapper! { ... } vs. wrapper!( ... );
The syntax wrapper! { ... } is equivalent to wrapper!( ... );. The
parenthesized form is preferred, as it is better supported by rustfmt.
§Limitation on generic parameters
Due to the inherent limitations of declarative macros, some complex syntax related to generic parameters is not supported.
-
A trait bound with more than one token like
?Sizedis not supported:ⓘwrapper_lite::wrapper!( // 👇 pub struct HolyMolyCow<'a, P: ?Sized>(&'a P); ); -
A trailing comma after the last generic parameter is not supported:
ⓘwrapper_lite::wrapper!( // 👇 pub struct HolyMolyCow<'a, P: Default,>(&'a P); ); -
whereclauses are not supported. There is currently no workaround:ⓘwrapper_lite::wrapper!( pub struct HolyMolyCow<'a, P>(&'a P) where P: ?Sized + Clone; );
The #[bound(...)] attribute serves as a partial workaround for the
limitations above:
wrapper_lite::wrapper!(
#[bound(P: ?Sized + Clone)]
pub struct HolyMolyCow<'a, P = ::core::marker::PhantomData<()>>(&'a P);
);§Limitation on conditional compilation attribute #[cfg(...)]
This macro can correctly handle conditional compilation attribute
#[cfg(...)] at the struct level currently. However, due to the
inherent complexity limitations of declarative macros, #[cfg(...)] on
struct fields are not supported now. This will affect scenarios involving
the construction of wrapper types, such as implementing the From trait,
etc.