use std::{collections::HashSet, fmt::Display, hash::Hasher, marker::PhantomData};
use rand::{distributions::Standard, thread_rng, Rng};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum Errors {
#[error("Missing <{0}> byte from byte-array")]
MissingIndicatorByte(u8),
#[error("{0}")]
Custom(String),
}
impl Errors {
pub fn new<S: AsRef<str>>(mesg: S) -> Self {Self::Custom(mesg.as_ref().to_string())}
}
pub trait Space {
fn indicator() -> u8;
fn length() -> usize {
16
}
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Hash)]
pub struct Id<S: Space> {
indicator: u8,
bytes: Vec<u8>,
_marker: PhantomData<S>,
}
impl<S: Space> Id<S> {
fn new(bytes: Vec<u8>) -> Id<S> {
Self {
indicator: S::indicator(),
bytes,
_marker: PhantomData,
}
}
pub fn create(bytes: Vec<u8>) -> Result<Self, Errors> {
if bytes.len() != S::length() + 1 {
return Err(Errors::new("invalid-length"));
};
if bytes[0] != S::indicator() {
return Err(Errors::new("incorrect-indicator"));
};
Ok(Self::new(bytes.to_vec()))
}
pub fn same_space(&self, _other: Id<S>) -> bool {
true
}
pub fn random() -> Self {
let randomized = thread_rng().sample_iter(Standard).take(S::length()).collect();
Self::new(randomized)
}
}
impl<S: Space> PartialEq<Vec<u8>> for Id<S> {
fn eq(&self, other: &Vec<u8>) -> bool {
if self.indicator == other[0] {
self.bytes == other[1..S::length()]
} else {
false
}
}
}
impl<S: Space> TryFrom<&[u8]> for Id<S> {
type Error = Errors;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
Self::create(value.to_vec())
}
}
pub struct TestingSpace;
impl Space for TestingSpace {
fn length() -> usize {
20
}
fn indicator() -> u8 {
0
}
}
pub type TestingId = Id<TestingSpace>;
#[derive(Debug, Clone)]
pub struct Ids<S: Space>(HashSet<Id<S>>);
impl<S: Space> Ids<S> {
pub fn len(&self) -> usize {self.0.len()}
pub fn is_empty(&self) -> bool {self.0.is_empty()}
}
impl<S: Space> PartialEq for Ids<S> {
fn eq(&self, other: &Self) -> bool {
if self.len() != other.len() {
return false
};
let zipped: Vec<(&Id<S>, &Id<S>)> = self.0.iter().zip(other.0.iter()).collect();
todo!()
}
}