feat: document and test newtype and experimental marker
`marker has been split out from newtype as I'm unused it has a valid use case, so I've placed under experimental. It is still accessed via `kx_utils::marker` despite the location of the module.
This commit is contained in:
parent
8561bee50a
commit
d4e582fe2c
5 changed files with 178 additions and 23 deletions
22
lcov.info
22
lcov.info
|
@ -0,0 +1,22 @@
|
||||||
|
TN:
|
||||||
|
SF:/Volumes/workplace/projects/kx-utils/src/experimental/to_string.rs
|
||||||
|
FN:7,s
|
||||||
|
FNF:1
|
||||||
|
FNDA:0,s
|
||||||
|
DA:7,0
|
||||||
|
DA:8,0
|
||||||
|
LF:2
|
||||||
|
LH:0
|
||||||
|
end_of_record
|
||||||
|
TN:
|
||||||
|
SF:/Volumes/workplace/projects/kx-utils/src/newtype.rs
|
||||||
|
FNF:0
|
||||||
|
DA:37,9
|
||||||
|
DA:38,9
|
||||||
|
DA:42,1
|
||||||
|
DA:43,1
|
||||||
|
DA:47,0
|
||||||
|
DA:48,0
|
||||||
|
LF:6
|
||||||
|
LH:4
|
||||||
|
end_of_record
|
72
src/experimental/marker.rs
Normal file
72
src/experimental/marker.rs
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
//
|
||||||
|
|
||||||
|
/// Defines a marker type with [Clone], [Copy], [Debug], [Display] nad [PartialEq].
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use kx_utils::marker;
|
||||||
|
/// marker!(Token, "Has no inner value");
|
||||||
|
/// let token = Token;
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// This is the equivalent of:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// #[doc = "Has no inner value"]
|
||||||
|
/// #[derive(
|
||||||
|
/// Clone,
|
||||||
|
/// Copy,
|
||||||
|
/// Debug,
|
||||||
|
/// derive_more::Display,
|
||||||
|
/// PartialEq,
|
||||||
|
/// )]
|
||||||
|
/// pub struct Token;
|
||||||
|
/// let token = Token;
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! marker {
|
||||||
|
($name:ident, $docs:literal) => {
|
||||||
|
#[doc = $docs]
|
||||||
|
#[derive(Clone, Copy, Debug, derive_more::Display, PartialEq)]
|
||||||
|
pub struct $name;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
// a newtype with no inner value
|
||||||
|
marker!(A, "a type");
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn marker_is_equals() {
|
||||||
|
assert_eq!(A, A);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn marker_is_clone() {
|
||||||
|
let a1 = A;
|
||||||
|
#[allow(clippy::clone_on_copy)]
|
||||||
|
let a2 = a1.clone();
|
||||||
|
assert_eq!(a1, a2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn marker_is_copy() {
|
||||||
|
let a1 = A;
|
||||||
|
let a2 = a1;
|
||||||
|
fn consume(_a: A) {}
|
||||||
|
consume(a1);
|
||||||
|
assert_eq!(a2, a1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn marker_is_debug() {
|
||||||
|
assert_eq!(format!("{:?}", A), "A");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn marker_is_display() {
|
||||||
|
assert_eq!(format!("{}", A), "A");
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ mod kameo;
|
||||||
#[cfg(feature = "use-kxio")]
|
#[cfg(feature = "use-kxio")]
|
||||||
mod kxio;
|
mod kxio;
|
||||||
|
|
||||||
|
mod marker;
|
||||||
mod to_string;
|
mod to_string;
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
//
|
//
|
||||||
mod experimental;
|
pub mod experimental;
|
||||||
mod newtype;
|
mod newtype;
|
||||||
|
|
104
src/newtype.rs
104
src/newtype.rs
|
@ -1,27 +1,24 @@
|
||||||
//
|
//
|
||||||
|
/// Defines a new type that wraps another type.
|
||||||
|
///
|
||||||
|
/// You can specify an optional number of additional traits to be derived after the wrapped type.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use kx_utils::newtype;
|
||||||
|
/// newtype!(Username, String, derive_more::Display, "The login name for the user");
|
||||||
|
/// let username = Username::new("bob");
|
||||||
|
/// assert_eq!(username.as_ref(), "bob");
|
||||||
|
/// assert_eq!(format!("{username}"), r"bob"); // because `derive_more::Display`
|
||||||
|
/// assert_eq!(format!("{username:?}"), r#"Username("bob")"#);
|
||||||
|
/// let peeled = username.peel(); // moves value out of `username`
|
||||||
|
/// assert_eq!(peeled, "bob".to_string());
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// In this example, [Username] also derives [derive_more::Display].
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! newtype {
|
macro_rules! newtype {
|
||||||
($name:ident, $docs:literal) => {
|
|
||||||
#[doc = $docs]
|
|
||||||
#[derive(
|
|
||||||
Clone,
|
|
||||||
Copy,
|
|
||||||
Default,
|
|
||||||
Debug,
|
|
||||||
derive_more::Display,
|
|
||||||
derive_more::From,
|
|
||||||
PartialEq,
|
|
||||||
Eq,
|
|
||||||
PartialOrd,
|
|
||||||
Ord,
|
|
||||||
Hash,
|
|
||||||
derive_more::AsRef,
|
|
||||||
derive_more::Constructor,
|
|
||||||
serde::Serialize,
|
|
||||||
serde::Deserialize,
|
|
||||||
)]
|
|
||||||
pub struct $name;
|
|
||||||
};
|
|
||||||
($name:ident, $type:ty $(, $derive:ty)*, $docs:literal) => {
|
($name:ident, $type:ty $(, $derive:ty)*, $docs:literal) => {
|
||||||
#[doc = $docs]
|
#[doc = $docs]
|
||||||
#[derive(
|
#[derive(
|
||||||
|
@ -31,7 +28,6 @@ macro_rules! newtype {
|
||||||
PartialEq,
|
PartialEq,
|
||||||
Eq,
|
Eq,
|
||||||
derive_more::AsRef,
|
derive_more::AsRef,
|
||||||
derive_more::Deref,
|
|
||||||
serde::Serialize,
|
serde::Serialize,
|
||||||
serde::Deserialize,
|
serde::Deserialize,
|
||||||
$($derive),*
|
$($derive),*
|
||||||
|
@ -54,3 +50,67 @@ macro_rules! newtype {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use derive_more::Display;
|
||||||
|
|
||||||
|
// a newtype with a String inner value
|
||||||
|
newtype!(A, String, "a type");
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn newtype_reflexive() {
|
||||||
|
let a = A::new("bob");
|
||||||
|
assert_eq!(a, a);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn newtype_new_is_equal_from() {
|
||||||
|
assert_eq!(A::new("bob"), A::from("bob".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn newtype_is_clone() {
|
||||||
|
let a1 = A::new("bob");
|
||||||
|
let a2 = a1.clone();
|
||||||
|
assert_eq!(a1, a2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn newtype_is_debug() {
|
||||||
|
assert_eq!(format!("{:?}", A::new("bob")), r#"A("bob")"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn newtype_with_derive_display_is_display() {
|
||||||
|
newtype!(B, String, Display, "displayable");
|
||||||
|
assert_eq!(format!("{}", B::new("bob")), r"bob");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn newtype_is_peelable() {
|
||||||
|
let a = A::new("bob");
|
||||||
|
assert_eq!(a.peel(), "bob");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn newtype_as_ref() {
|
||||||
|
let a = A::new("bob");
|
||||||
|
let b: &str = a.as_ref();
|
||||||
|
assert_eq!(b, "bob");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn newtype_serialize() {
|
||||||
|
let a = A::new("bob");
|
||||||
|
let s = serde_json::to_string(&a).unwrap();
|
||||||
|
assert_eq!(s, "\"bob\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn newtype_deserialize() {
|
||||||
|
let a = A::new("bob");
|
||||||
|
let s: A = serde_json::from_str("\"bob\"").unwrap();
|
||||||
|
assert_eq!(s, a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue