2 releases
0.1.1 | May 3, 2019 |
---|---|
0.1.0 | May 2, 2019 |
#50 in #owned
21 downloads per month
88KB
1.5K
SLoC
custom-slice
Proc-macros to define custom slice types easily (without users writing unsafe codes manually).
Usage
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]
.
Basic
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.- Any attributes for the types will be emitted if it is not
#[custom_slice(..)]
style.- You can specify
#[derive(Debug, Clone, Copy, ..)]
for the types.
- You can specify
- Visibility will be not modified.
- Instead of
pub
, you can use any valid visibility (such aspub(crate)
or nothing).
- Instead of
Constructor, error and validator
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.
- Specify constructor names, visilibily, and unsafety.
All attributes below are optional.
#[custom_slice(new_unchecked = ..)]
: constructor without validation.- This does NOT require validator.
- This returns
Owned
.
#[custom_slice(new_checked = ..)]
: constructor with validation.- This requires validator.
- This returns
Result<Owned, _>
.
#[custom_slice(new_unchecked_mut = ..)]
: constructor without validation.- This does NOT require validator.
- Available only for slice types.
- This returns
&mut Slice
.
#[custom_slice(new_checked_mut = ..)]
: constructor with validation.- This requires validator.
- Available only for slice types.
- This returns
Result<&mut Slice, _>
.
- Specify validator function.
- Optional.
- Validator function name can have any valid name, but should be defined in
the
define_slice_types_pair!
macro and should have#[custom_slice(validator)]
attribute. - Return type should be
std::result::Result<(), _>
.
- Specify Error type and mapping function.
- Use
#[custom_slice(error(type = "ErrorTypeName"))]
. - If you want to return modified error, use
#[custom_slice(error(type = "ErrorTypeName", map = "mapping_expr"))]
. type
is mandatory if you specifynew_checked
ornew_checked_mut
, butmap
is optional in such cases.mapping_expr
can be any function expression with typeFnOnce(ValidatorError, Inner) -> CtorError
.
- Use
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. */
}
}
Accessors
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);
}
- Specify accessor names, visilibily, and unsafety.
All attributes below are optional.
#[custom_slice(get_ref = ..)]
: reference getter.- This returns
&OwnedInner
or&SliceInner
.
- This returns
#[custom_slice(get_mut = ..)]
: mutable reference getter.- This returns
&mut OwnedInner
or&mut SliceInner
.
- This returns
#[custom_slice(into_inner = ..)]
: deconstructor.- This returns
OwnedInner
. - This is available only for owned types.
- This returns
Comments and attributes for functions
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);
}
Deriving traits
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:
Derive targets for owned types
std::borrow::*
BorrowMut
:impl std::borrow::BorrowMut<Slice> for Owned { /* .. */ }
std::cmp::*
PartialEq
:impl std::cmp::PartialEq<Owned> for Owned { /* .. */ }
- Requires
PartialEq<Slice> for Slice
. - Usual
#[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 forSlice
type, you should use#[custom_slice(derive(PartialEq))]
forOwned
type.
- Requires
PartialEqBulk
: Many impls using<Slice as PartialEq<Slice>>
.- Requires
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>
- Requires
PartialEqInnerBulk
: Many impls using<SliceInner as PartialEq<SliceInner>>
.- Requires
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>
- Requires
PartialOrd
,PartialOrdBulk
,PartialOrdInnerBulk
:PartialOrd
version of the correspondingPartialEq*
targets.- Requires the corresponding
PartialEq*
impls. - See description of the corresponding
PartialEq*
for detail.
- Requires the corresponding
std::convert::*
AsRefSlice
:impl std::convert::AsRef<Slice> for Owned { /* .. */ }
- Requires
AsRef<SliceInner>: OwnedInner
.
- Requires
AsRefSliceInner
:impl std::convert::AsRef<SliceInner> for Owned { /* .. */ }
- Requires
AsRef<SliceInner>: OwnedInner
.
- Requires
AsMutSlice
:impl std::convert::AsMut<Slice> for Owned { /* .. */ }
- Requires
AsMut<SliceInner>: OwnedInner
.
- Requires
AsMutSliceInner
:impl std::convert::AsMut<SliceInner> for Owned { /* .. */ }
- Requires
AsMut<SliceInner>: OwnedInner
.
- Requires
FromInner
:impl std::convert::From<OwnedInner> for Owned { /* .. */ }
- Requires validator to be absent.
IntoInner
:impl std::convert::From<Owned> for OwnedInner { /* .. */ }
TryFromInner
:impl std::convert::TryFrom<OwnedInner> for Owned { /* .. */ }
- Requires validator to be present.
std::ops::*
Deref
:impl std::ops::Deref for Owned { type Target = Slice; /* .. */ }
DerefMut
:impl std::ops::DerefMut for Owned { /* .. */ }
- Requires
Deref<Target = Slice> for Owned
.
- Requires
Derive targets for slice types
std::cmp::*
PartialEqBulk
: Many impls using<Slice as PartialEq<Slice>>
.- Requires
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>
- Requires
PartialEqInnerBulk
: Many impls using<SliceInner as PartialEq<SliceInner>>
.- Requires
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>
- Requires
PartialOrdBulk
,PartialOrdInnerBulk
:PartialOrd
version of the correspondingPartialEq*
targets.- Requires the corresponding
PartialEq*
impls. - See description of the corresponding
PartialEq*
for detail.
- Requires the corresponding
std::convert::*
AsRefSlice
:impl std::convert::AsRef<Slice> for Slice { /* .. */ }
- Requires
AsRef<SliceInner>: SliceInner
.
- Requires
AsRefSliceInner
:impl std::convert::AsRef<SliceInner> for Slice { /* .. */ }
- Requires
AsRef<SliceInner>: SliceInner
.
- Requires
AsMutSlice
:impl std::convert::AsMut<Slice> for Slice { /* .. */ }
- Requires
AsMut<SliceInner>: SliceInner
.
- Requires
AsMutSliceInner
:impl std::convert::AsMut<SliceInner> for Slice { /* .. */ }
- Requires
AsMut<SliceInner>: SliceInner
.
- Requires
FromInner
:impl<'a> std::convert::From<&'a SliceInner> for &'a Slice { /* .. */ }
- Requires validator to be absent.
FromInnerMut
:impl<'a> std::convert::From<&'a mut SliceInner> for &'a mut Slice { /* .. */ }
- Requires validator to be absent.
IntoArc
:impl std::convert::From<&Slice> for std::sync::Arc<Slice> { /* .. */ }
- Requires
Arc<SliceInner>: From<&SliceInner>
.
- Requires
IntoBox
:impl std::convert::From<&Slice> for std::boxed::Box<Slice> { /* .. */ }
- Requires
Box<SliceInner>: From<&SliceInner>
.
- Requires
IntoRc
:impl std::convert::From<&Slice> for std::rc::Rc<Slice> { /* .. */ }
- Requires
Rc<SliceInner>: From<&SliceInner>
.
- Requires
TryFromInner
:impl<'a> std::convert::TryFrom<&'a SliceInner> for &'a Slice { /* .. */ }
- Requires validator to be present.
TryFromInnerMut
:impl<'a> std::convert::TryFrom<&'a mut SliceInner> for &'a mut Slice { /* .. */ }
- Requires validator to be present.
std::default::*
DefaultBox
:impl std::default::Default for Box<Slice> { /* .. */ }
- Requires
Box<SliceInner>: Default
.
- Requires
DefaultRef
:impl std::default::Default for &Slice { /* .. */ }
- Requires
&SliceInner: Default
.
- Requires
DefaultRefMut
:impl std::default::Default for &mut Slice { /* .. */ }
- Requires
&mut SliceInner: Default
.
- Requires
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
.
- Requires
License
Licensed under either of
- Apache License, Version 2.0, (LICENSE-APACHE.txt or https://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT.txt or https://opensource.org/licenses/MIT)
at your option.
Contribution
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.
Dependencies
~2MB
~48K SLoC