Crates.io | custom-slice-macros |
lib.rs | custom-slice-macros |
version | 0.1.1 |
source | src |
created_at | 2019-05-02 14:19:55.32564 |
updated_at | 2019-05-03 17:17:04.660363 |
description | Utilities to define custom slice types |
homepage | |
repository | https://github.com/lo48576/custom-slice |
max_upload_size | |
id | 131552 |
size | 140,945 |
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:
/// Owned slice.
// Sized type.
pub struct Owned(OwnedInner);
/// Borrowed slice.
// Unsized slice type.
pub struct Slice(SliceInner);
impl std::borrow::Borrow<Slice> for Owned { /* .. */ }
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]
.
custom_slice_macros::define_slice_types_pair! {
/// Owned slice.
#[custom_slice(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:
custom_slice_macros::define_slice_types_pair! {
/// Owned slice.
// Assume `owned_inner: OwnedInner`.
#[custom_slice(owned)]
//let _: Owned = Owned::new(owned_inner);
#[custom_slice(new_unchecked = "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:
custom_slice_macros::define_slice_types_pair! {
/// Owned slice.
// Assume `owned_inner: OwnedInner`.
#[custom_slice(owned)]
//let _: Owned = unsafe { Owned::new_unchecked(owned_inner) };
#[custom_slice(new_unchecked = "unsafe fn new_unchecked")]
//let _: Result<Owned, ErrorWithInner> = Owned::new(owned_inner);
#[custom_slice(new_checked = "pub fn new")]
#[custom_slice(error(
type = "ErrorWithInner",
map = "{|e, v| Error { error: e, value: v } }"
))]
pub struct Owned(OwnedInner);
/// 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.
custom_slice_macros::define_slice_types_pair! {
/// Owned slice.
// Assume `owned: Owned` and `mut owned_mut: Owned`.
#[custom_slice(owned)]
//let _: &OwnedInner = owned.get();
#[custom_slice(get_ref = "pub fn get")]
//let _: &mut OwnedInner = owned_mut.get_mut();
#[custom_slice(get_mut = "fn get_mut")]
//let _: OwnedInner = owned.into_inner();
#[custom_slice(into_inner = "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
.In attributes to specify functions (such as get_ref
and new_unchecked
), you
can specify attributes and comments.
For example:
custom_slice_macros::define_slice_types_pair! {
/// Owned slice.
#[custom_slice(owned)]
#[custom_slice(get_ref = "#[allow(missing_docs)] pub fn get")]
#[custom_slice(get_mut = "#[deny(dead_code)] fn get_mut")]
#[custom_slice(into_inner = "
/// Extracts the inner owned slice.
pub fn into_inner
")]
pub struct Owned(OwnedInner);
/// Borrowed slice.
#[repr(transparent)]
#[custom_slice(slice)]
#[custom_slice(new_unchecked = "
/// Creates a new `Slice` without validation.
#[deprecated (since = \"0.2.0\", note = \"Use `new_checked`\")]
pub fn new_unchecked
")]
#[custom_slice(new_checked = "
/// Creates a new `Slice` if the given value is valid.
pub fn new_checked
")]
pub struct Slice(SliceInner);
}
custom_slice_macros::define_slice_types_pair!
supports generating impls which
should possibly require unsafe operations.
custom_slice_macros::define_slice_types_pair! {
/// Owned slice.
#[custom_slice(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:
std::borrow::*
BorrowMut
:
impl std::borrow::BorrowMut<Slice> for Owned { /* .. */ }
std::cmp::*
PartialEq
:
impl std::cmp::PartialEq<Owned> for Owned { /* .. */ }
PartialEq<Slice> for Slice
.#[derive(PartialEq)]
uses
<OwnedInner as PartialEq<OwnedInner>>
as its internal
implementation, but #[custom_slice(derive(PartialEq))]
uses
<Slice as PartialEq<Slice>>
internally.
If you define custom comparison for Slice
type, you should use
#[custom_slice(derive(PartialEq))]
for Owned
type.PartialEqBulk
: Many impls using <Slice as PartialEq<Slice>>
.
PartialEq<Slice> for Slice
.impl PartialEq<Slice> for Owned
impl PartialEq<Owned> for Slice
impl PartialEq<&Slice> for Owned
impl PartialEq<Owned> for &Slice
impl PartialEq<Cow<Slice>> for Owned
impl PartialEq<Owned> for Cow<Slice>
PartialEqInnerBulk
: Many impls using
<SliceInner as PartialEq<SliceInner>>
.
PartialEq<SliceInner> for SliceInner
.impl PartialEq<SliceInner> for Owned
impl PartialEq<Owned> for SliceInner
impl PartialEq<&SliceInner> for Owned
impl PartialEq<Owned> for &SliceInner
impl PartialEq<Cow<SliceInner>> for Owned
impl PartialEq<Owned> for Cow<SliceInner>
PartialOrd
, PartialOrdBulk
, PartialOrdInnerBulk
: PartialOrd
version of the corresponding PartialEq*
targets.
PartialEq*
impls.PartialEq*
for detail.std::convert::*
AsRefSlice
:
impl std::convert::AsRef<Slice> for Owned { /* .. */ }
AsRef<SliceInner>: OwnedInner
.AsRefSliceInner
:
impl std::convert::AsRef<SliceInner> for Owned { /* .. */ }
AsRef<SliceInner>: OwnedInner
.AsMutSlice
:
impl std::convert::AsMut<Slice> for Owned { /* .. */ }
AsMut<SliceInner>: OwnedInner
.AsMutSliceInner
:
impl std::convert::AsMut<SliceInner> for Owned { /* .. */ }
AsMut<SliceInner>: OwnedInner
.FromInner
:
impl std::convert::From<OwnedInner> for Owned { /* .. */ }
IntoInner
:
impl std::convert::From<Owned> for OwnedInner { /* .. */ }
TryFromInner
:
impl std::convert::TryFrom<OwnedInner> for Owned { /* .. */ }
std::ops::*
Deref
:
impl std::ops::Deref for Owned { type Target = Slice; /* .. */ }
DerefMut
:
impl std::ops::DerefMut for Owned { /* .. */ }
Deref<Target = Slice> for Owned
.std::cmp::*
PartialEqBulk
: Many impls using <Slice as PartialEq<Slice>>
.
PartialEq<Slice> for Slice
.impl PartialEq<&Slice> for Slice
impl PartialEq<Slice> for &Slice
impl PartialEq<Cow<Slice>> for Slice
impl PartialEq<Slice> for Cow<Slice>
PartialEqInnerBulk
: Many impls using
<SliceInner as PartialEq<SliceInner>>
.
PartialEq<SliceInner> for SliceInner
.impl PartialEq<SliceInner> for Slice
impl PartialEq<Slice> for SliceInner
impl PartialEq<&SliceInner> for Slice
impl PartialEq<Slice> for &SliceInner
impl PartialEq<OwnedInner> for Slice
impl PartialEq<Slice> for OwnedInner
impl PartialEq<Cow<SliceInner>> for Slice
impl PartialEq<Slice> for Cow<SliceInner>
impl PartialEq<SliceInner> for &Slice
impl PartialEq<&Slice> for SliceInner
impl PartialEq<OwnedInner> for &Slice
impl PartialEq<&Slice> for OwnedInner
impl PartialEq<Cow<SliceInner>> for &Slice
impl PartialEq<&Slice> for Cow<SliceInner>
PartialOrdBulk
, PartialOrdInnerBulk
: PartialOrd
version of the corresponding PartialEq*
targets.
PartialEq*
impls.PartialEq*
for detail.std::convert::*
AsRefSlice
:
impl std::convert::AsRef<Slice> for Slice { /* .. */ }
AsRef<SliceInner>: SliceInner
.AsRefSliceInner
:
impl std::convert::AsRef<SliceInner> for Slice { /* .. */ }
AsRef<SliceInner>: SliceInner
.AsMutSlice
:
impl std::convert::AsMut<Slice> for Slice { /* .. */ }
AsMut<SliceInner>: SliceInner
.AsMutSliceInner
:
impl std::convert::AsMut<SliceInner> for Slice { /* .. */ }
AsMut<SliceInner>: SliceInner
.FromInner
:
impl<'a> std::convert::From<&'a SliceInner> for &'a Slice { /* .. */ }
FromInnerMut
:
impl<'a> std::convert::From<&'a mut SliceInner> for &'a mut Slice { /* .. */ }
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>
.TryFromInner
:
impl<'a> std::convert::TryFrom<&'a SliceInner> for &'a Slice { /* .. */ }
TryFromInnerMut
:
impl<'a> std::convert::TryFrom<&'a mut SliceInner> for &'a mut Slice { /* .. */ }
std::default::*
DefaultBox
:
impl std::default::Default for Box<Slice> { /* .. */ }
Box<SliceInner>: Default
.DefaultRef
:
impl std::default::Default for &Slice { /* .. */ }
&SliceInner: Default
.DefaultRefMut
:
impl std::default::Default for &mut Slice { /* .. */ }
&mut SliceInner: Default
.std::ops::*
Deref
:
impl std::ops::Deref for Slice { type Target = SliceInner; /* .. */ }
DerefMut
:
impl std::ops::DerefMut for Slice { /* .. */ }
Requires Deref<Target = SliceInner> for Slice
.
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.