| Crates.io | custom-slice-macros |
| lib.rs | custom-slice-macros |
| version | 0.1.1 |
| created_at | 2019-05-02 14:19:55.32564+00 |
| updated_at | 2019-05-03 17:17:04.660363+00 |
| 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 Ownedimpl PartialEq<Owned> for Sliceimpl PartialEq<&Slice> for Ownedimpl PartialEq<Owned> for &Sliceimpl PartialEq<Cow<Slice>> for Ownedimpl PartialEq<Owned> for Cow<Slice>PartialEqInnerBulk: Many impls using
<SliceInner as PartialEq<SliceInner>>.
PartialEq<SliceInner> for SliceInner.impl PartialEq<SliceInner> for Ownedimpl PartialEq<Owned> for SliceInnerimpl PartialEq<&SliceInner> for Ownedimpl PartialEq<Owned> for &SliceInnerimpl PartialEq<Cow<SliceInner>> for Ownedimpl 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 Sliceimpl PartialEq<Slice> for &Sliceimpl PartialEq<Cow<Slice>> for Sliceimpl PartialEq<Slice> for Cow<Slice>PartialEqInnerBulk: Many impls using
<SliceInner as PartialEq<SliceInner>>.
PartialEq<SliceInner> for SliceInner.impl PartialEq<SliceInner> for Sliceimpl PartialEq<Slice> for SliceInnerimpl PartialEq<&SliceInner> for Sliceimpl PartialEq<Slice> for &SliceInnerimpl PartialEq<OwnedInner> for Sliceimpl PartialEq<Slice> for OwnedInnerimpl PartialEq<Cow<SliceInner>> for Sliceimpl PartialEq<Slice> for Cow<SliceInner>impl PartialEq<SliceInner> for &Sliceimpl PartialEq<&Slice> for SliceInnerimpl PartialEq<OwnedInner> for &Sliceimpl PartialEq<&Slice> for OwnedInnerimpl PartialEq<Cow<SliceInner>> for &Sliceimpl 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.