use core::fmt::Display;
use cheap_clone::CheapClone;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
#[cfg_attr(feature = "rkyv", rkyv(compare(PartialEq)))]
pub struct Node<I, A> {
id: I,
address: A,
}
impl<I: Display, A: Display> Display for Node<I, A> {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}({})", self.id, self.address)
}
}
impl<I, A> From<(I, A)> for Node<I, A> {
#[inline]
fn from((id, address): (I, A)) -> Self {
Self { id, address }
}
}
impl<I, A> Node<I, A> {
#[inline]
pub const fn new(id: I, address: A) -> Self {
Self { id, address }
}
#[inline]
pub const fn id(&self) -> &I {
&self.id
}
#[inline]
pub const fn address(&self) -> &A {
&self.address
}
#[inline]
pub fn set_address(&mut self, address: A) -> &mut Self {
self.address = address;
self
}
#[inline]
pub fn set_id(&mut self, id: I) -> &mut Self {
self.id = id;
self
}
#[inline]
pub fn with_address(mut self, address: A) -> Self {
self.address = address;
self
}
#[inline]
pub fn with_id(mut self, id: I) -> Self {
self.id = id;
self
}
#[inline]
pub fn into_components(self) -> (I, A) {
(self.id, self.address)
}
#[inline]
pub fn into_id(self) -> I {
self.id
}
#[inline]
pub fn into_address(self) -> A {
self.address
}
#[inline]
pub fn map_address<U>(self, f: impl FnOnce(A) -> U) -> Node<I, U> {
Node {
id: self.id,
address: f(self.address),
}
}
#[inline]
pub fn map_id<U>(self, f: impl FnOnce(I) -> U) -> Node<U, A> {
Node {
id: f(self.id),
address: self.address,
}
}
#[inline]
pub fn map<U, V>(self, f: impl FnOnce(I, A) -> (U, V)) -> Node<U, V> {
let (id, address) = f(self.id, self.address);
Node { id, address }
}
}
impl<I: CheapClone, A: CheapClone> CheapClone for Node<I, A> {
#[inline]
fn cheap_clone(&self) -> Self {
Self {
id: self.id.cheap_clone(),
address: self.address.cheap_clone(),
}
}
}
#[cfg(feature = "rkyv")]
const _: () = {
use rkyv::Archive;
impl<I: Archive, A: Archive> Clone for ArchivedNode<I, A>
where
I::Archived: Clone,
A::Archived: Clone,
{
#[inline]
fn clone(&self) -> Self {
Self {
id: self.id.clone(),
address: self.address.clone(),
}
}
}
impl<I: Archive, A: Archive> CheapClone for ArchivedNode<I, A>
where
I::Archived: CheapClone,
A::Archived: CheapClone,
{
#[inline]
fn cheap_clone(&self) -> Self {
Self {
id: self.id.cheap_clone(),
address: self.address.cheap_clone(),
}
}
}
impl<I: Archive, A: Archive> Copy for ArchivedNode<I, A>
where
I::Archived: Copy,
A::Archived: Copy,
{
}
impl<I: Archive, A: Archive> PartialEq for ArchivedNode<I, A>
where
I::Archived: PartialEq,
A::Archived: PartialEq,
{
#[inline]
fn eq(&self, other: &Self) -> bool {
self.id == other.id && self.address == other.address
}
}
impl<I: Archive, A: Archive> Eq for ArchivedNode<I, A>
where
I::Archived: Eq,
A::Archived: Eq,
{
}
impl<I: Archive, A: Archive> core::hash::Hash for ArchivedNode<I, A>
where
I::Archived: core::hash::Hash,
A::Archived: core::hash::Hash,
{
#[inline]
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.id.hash(state);
self.address.hash(state);
}
}
impl<I: Archive, A: Archive> core::fmt::Debug for ArchivedNode<I, A>
where
I::Archived: core::fmt::Debug,
A::Archived: core::fmt::Debug,
{
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ArchivedNode")
.field("id", &self.id)
.field("address", &self.address)
.finish()
}
}
impl<I: Archive, A: Archive> core::fmt::Display for ArchivedNode<I, A>
where
I::Archived: core::fmt::Display,
A::Archived: core::fmt::Display,
{
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}({})", self.id, self.address)
}
}
};
#[cfg(feature = "arbitrary")]
const _: () = {
use arbitrary::{Arbitrary, Unstructured};
impl<'a, I: Arbitrary<'a>, A: Arbitrary<'a>> Arbitrary<'a> for Node<I, A> {
#[inline]
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
Ok(Self::new(I::arbitrary(u)?, A::arbitrary(u)?))
}
}
};
#[cfg(feature = "quickcheck")]
const _: () = {
use quickcheck::{Arbitrary, Gen};
impl<I: Arbitrary, A: Arbitrary> Arbitrary for Node<I, A> {
#[inline]
fn arbitrary(g: &mut Gen) -> Self {
Self::new(I::arbitrary(g), A::arbitrary(g))
}
}
};
#[cfg(all(any(feature = "std", feature = "alloc"), test))]
mod tests {
#[allow(unused_imports)]
use super::*;
#[cfg(feature = "serde")]
fn random(size: usize) -> Node<smol_str_0_3::SmolStr, u64> {
use rand::{RngExt, distr::Alphanumeric, rng};
let id = rng()
.sample_iter(Alphanumeric)
.take(size)
.collect::<Vec<u8>>();
Node::new(
smol_str_0_3::SmolStr::from(String::from_utf8(id).unwrap()),
rng().random(),
)
}
#[test]
#[cfg(feature = "arbitrary")]
fn test_node_access() {
use arbitrary::{Arbitrary, Unstructured};
let mut data = vec![0; 1024];
rand::fill(&mut data[..]);
let mut data = Unstructured::new(&data);
let mut node = Node::<std::sync::Arc<String>, u64>::arbitrary(&mut data).unwrap();
node.set_id(String::from("test").into());
node.set_address(100);
assert_eq!(node.id().as_str(), "test");
assert_eq!(node.address(), &100);
let node = node
.cheap_clone()
.with_id(String::from("test2").into())
.with_address(200);
assert_eq!(node.id().as_str(), "test2");
assert_eq!(node.address(), &200);
let (id, address) = node.into_components();
assert_eq!(id.as_str(), "test2");
assert_eq!(address, 200);
let node = Node::from(("test3", 300));
assert_eq!(*node.id(), "test3");
assert_eq!(node.address(), &300);
assert_eq!(node.into_id(), "test3");
assert_eq!(node.into_address(), 300);
#[cfg(feature = "std")]
println!("{}", node);
}
#[cfg(feature = "serde")]
#[test]
fn test_serde() {
let node = random(10);
let serialized = serde_json::to_string(&node).unwrap();
let deserialized: Node<smol_str_0_3::SmolStr, u64> = serde_json::from_str(&serialized).unwrap();
assert_eq!(node, deserialized);
let node = random(100);
let serialized = serde_json::to_string(&node).unwrap();
let deserialized: Node<smol_str_0_3::SmolStr, u64> = serde_json::from_str(&serialized).unwrap();
assert_eq!(node, deserialized);
}
#[cfg(all(feature = "serde", feature = "quickcheck"))]
#[quickcheck_macros::quickcheck]
fn fuzzy_serde(node: Node<String, u64>) -> bool {
let serialized = serde_json::to_string(&node).unwrap();
let deserialized: Node<String, u64> = serde_json::from_str(&serialized).unwrap();
node == deserialized
}
}