feat: document and test newtype and experimental marker
All checks were successful
Test / build (map[name:nightly]) (push) Successful in 58s
Test / build (map[name:stable]) (push) Successful in 1m16s
Release Please / Release-plz (push) Successful in 9s

`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:
Paul Campbell 2025-01-09 21:27:08 +00:00
parent 8561bee50a
commit d4e582fe2c
5 changed files with 178 additions and 23 deletions

View file

@ -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

View 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");
}
}

View file

@ -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)]

View file

@ -1,3 +1,3 @@
// //
mod experimental; pub mod experimental;
mod newtype; mod newtype;

View file

@ -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);
}
}