Proc-macros to define custom slice types easily (without users writing unsafe codes manually).
Consider the case you want to define slice types as below:
```rust /// Owned slice. // Sized type. pub struct Owned(OwnedInner);
/// Borrowed slice. // Unsized slice type. pub struct Slice(SliceInner);
impl std::borrow::Borrow
impl std::borrow::ToOwned for Slice { type Owned = Owned;
// ..
} ```
For example, if Owned
is String
and Slice
is str
, OwnedInner
is
Vec<u8>
and SliceInner
is [u8]
.
```rust customslicemacros::defineslicetypespair! { /// Owned slice. #[customslice(owned)] pub struct Owned(OwnedInner);
/// Borrowed slice.
#[repr(transparent)]
#[custom_slice(slice)]
pub struct Slice(SliceInner);
} ```
By this way, std::borrow::Borrow
and std::borrow::ToOwned
is automatically
implemented.
Note that:
#[repr(transparent)]
or #[repr(C)]
is required for slice type.#[custom_slice(..)]
style.
#[derive(Debug, Clone, Copy, ..)]
for the types.pub
, you can use any valid visibility
(such as pub(crate)
or nothing).You can specify validator functions and error types for constructors.
This is useful for types which can have limited values (compared to the inner
types).
For example, Vec<u8>
can have any binary data, but String
can have valid
UTF-8 sequences.
#[custom_slice(new_unchecked = ..)]
: constructor without validation.
Owned
.#[custom_slice(new_checked = ..)]
: constructor with validation.
Result<Owned, _>
.#[custom_slice(new_unchecked_mut = ..)]
: constructor without validation.
&mut Slice
.#[custom_slice(new_checked_mut = ..)]
: constructor with validation.
Result<&mut Slice, _>
.define_slice_types_pair!
macro and should have
#[custom_slice(validator)]
attribute.std::result::Result<(), _>
.#[custom_slice(error(type = "ErrorTypeName"))]
.#[custom_slice(error(type = "ErrorTypeName", map = "mapping_expr"))]
.type
is mandatory if you specify new_checked
or new_checked_mut
,
but map
is optional in such cases.mapping_expr
can be any function expression with type
FnOnce(ValidatorError, Inner) -> CtorError
.Example without validator:
``rust
custom_slice_macros::define_slice_types_pair! {
/// Owned slice.
// Assume
ownedinner: OwnedInner`.
#[customslice(owned)]
//let : Owned = Owned::new(ownedinner);
#[customslice(newunchecked = "fn new")]
pub struct Owned(OwnedInner);
/// Borrowed slice.
#[repr(transparent)]
// Assume `slice_inner_ref: &Slice` and `slice_inner_mut: &mut Slice`.
#[custom_slice(slice)]
//let _: &Slice = Slice::new(slice_inner_ref);
#[custom_slice(new = "fn new")]
//let _: &mut Slice = Slice::new_mut(slice_inner_mut);
#[custom_slice(new_mut = "fn new_mut")]
pub struct Slice(SliceInner);
} ```
Example with validator:
``rust
custom_slice_macros::define_slice_types_pair! {
/// Owned slice.
// Assume
ownedinner: OwnedInner`.
#[customslice(owned)]
//let : Owned = unsafe { Owned::newunchecked(ownedinner) };
#[customslice(newunchecked = "unsafe fn newunchecked")]
//let : Result
/// Borrowed slice.
#[repr(transparent)]
// Assume `slice_inner_ref: &Slice` and `slice_inner_mut: &mut Slice`.
#[custom_slice(slice)]
//let _: &Slice = unsafe { Slice::new_unchecked(slice_inner_ref) };
#[custom_slice(new_unchecked = "unsafe fn new_unchecked")]
//let _: &mut Slice = unsafe { Slice::new_unchecked_mut(slice_inner_mut) };
#[custom_slice(new_unchecked_mut = "unsafe fn new_unchecked_mut")]
//let _: Result<&Slice, Error> = Slice::new(slice_inner_ref);
#[custom_slice(new_checked = "pub fn new")]
//let _: Result<&mut Slice, Error> = Slice::new_mut(slice_inner_mut);
#[custom_slice(new_checked_mut = "pub fn new_mut")]
#[custom_slice(error(type = "Error"))]
pub struct Slice(SliceInner);
/// Validates the given data.
///
/// Returns `Ok(())` for valid data, `Err(_)` for invalid data.
#[custom_slice(validator)]
fn validate(s: &SliceInner) -> Result<(), Error> {
/* Do the validation. */
}
} ```
You can define accessors to the inner types with meaningful name.
``rust
custom_slice_macros::define_slice_types_pair! {
/// Owned slice.
// Assume
owned: Ownedand
mut ownedmut: Owned`.
#[customslice(owned)]
//let : &OwnedInner = owned.get();
#[customslice(getref = "pub fn get")]
//let _: &mut OwnedInner = ownedmut.getmut();
#[customslice(getmut = "fn getmut")]
//let : OwnedInner = owned.intoinner();
#[customslice(intoinner = "pub fn into_inner")]
pub struct Owned(OwnedInner);
/// Borrowed slice.
// Assume `slice_ref: &Slice` and `slice_mut: &mut Slice`.
#[repr(transparent)]
#[custom_slice(slice)]
//let _: &SliceInner = slice_ref.get();
#[custom_slice(get_ref = "pub fn get")]
//let _: &mut SliceInner = slice_mut.get_mut();
#[custom_slice(get_mut = "fn get_mut")]
pub struct Slice(SliceInner);
} ```
#[custom_slice(get_ref = ..)]
: reference getter.
&OwnedInner
or &SliceInner
.#[custom_slice(get_mut = ..)]
: mutable reference getter.
&mut OwnedInner
or &mut SliceInner
.#[custom_slice(into_inner = ..)]
: deconstructor.
OwnedInner
.custom_slice_macros::define_slice_types_pair!
supports generating impls which
should possibly require unsafe operations.
```rust customslicemacros::defineslicetypespair! { /// Owned slice. #[customslice(owned)] #[custom_slice(derive(BorrowMut, Deref, DerefMut))] pub struct Owned(OwnedInner);
/// Borrowed slice.
#[repr(transparent)]
#[custom_slice(slice)]
#[custom_slice(derive(DefaultRef, DefaultRefMut))]
pub struct Slice(SliceInner);
} ```
The following derive targets are available:
BorrowMut
:
impl std::borrow::BorrowMut<Slice> for Owned { /* .. */ }
Deref
:
impl std::ops::Deref for Owned { type Target = Slice; /* .. */ }
DerefMut
:
impl std::ops::DerefMut for Owned { /* .. */ }
DefaultRef
:
impl std::default::Default for &Slice { /* .. */ }
&SliceInner: Default
.DefaultRefMut
:
impl std::default::Default for &mut Slice { /* .. */ }
&mut SliceInner: Default
.IntoArc
:
impl std::convert::From<&Slice> for std::sync::Arc<Slice> { /* .. */ }
Arc<SliceInner>: From<&SliceInner>
.IntoBox
:
impl std::convert::From<&Slice> for std::boxed::Box<Slice> { /* .. */ }
Box<SliceInner>: From<&SliceInner>
.IntoRc
:
impl std::convert::From<&Slice> for std::rc::Rc<Slice> { /* .. */ }
Rc<SliceInner>: From<&SliceInner>
.Licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.