#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use karpal_core::Semigroup;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct NonEmpty<C> {
inner: C,
}
impl<T> NonEmpty<Vec<T>> {
pub fn try_new(v: Vec<T>) -> Option<Self> {
if v.is_empty() {
None
} else {
Some(NonEmpty { inner: v })
}
}
pub fn from_parts(head: T, tail: Vec<T>) -> Self {
let mut v = tail;
v.insert(0, head);
NonEmpty { inner: v }
}
pub fn singleton(value: T) -> Self {
NonEmpty {
inner: [value].into(),
}
}
pub fn head(&self) -> &T {
&self.inner[0]
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
false
}
pub fn push(&mut self, value: T) {
self.inner.push(value);
}
pub fn as_slice(&self) -> &[T] {
&self.inner
}
pub fn into_vec(self) -> Vec<T> {
self.inner
}
pub fn iter(&self) -> core::slice::Iter<'_, T> {
self.inner.iter()
}
pub fn map<U>(self, f: impl FnMut(T) -> U) -> NonEmpty<Vec<U>> {
NonEmpty {
inner: self.inner.into_iter().map(f).collect(),
}
}
}
impl<T: Semigroup + Clone> Semigroup for NonEmpty<Vec<T>> {
fn combine(mut self, other: Self) -> Self {
self.inner.extend(other.inner);
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct Positive<T> {
value: T,
}
macro_rules! impl_positive_float {
($($t:ty),*) => {
$(
impl Positive<$t> {
pub fn try_new(v: $t) -> Option<Self> {
if v > 0.0 && v.is_finite() {
Some(Positive { value: v })
} else {
None
}
}
pub fn get(self) -> $t {
self.value
}
pub fn reciprocal(self) -> Self {
Positive { value: 1.0 / self.value }
}
}
)*
};
}
impl_positive_float!(f32, f64);
macro_rules! impl_positive_int {
($($t:ty),*) => {
$(
impl Positive<$t> {
pub fn try_new(v: $t) -> Option<Self> {
if v > 0 {
Some(Positive { value: v })
} else {
None
}
}
pub fn get(self) -> $t {
self.value
}
}
)*
};
}
impl_positive_int!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
macro_rules! impl_positive_unsigned {
($($t:ty),*) => {
$(
impl Positive<$t> {
pub fn from_nonzero(v: $t) -> Option<Self> {
if v > 0 {
Some(Positive { value: v })
} else {
None
}
}
}
)*
};
}
impl_positive_unsigned!(u8, u16, u32, u64, u128);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn non_empty_try_new() {
assert!(NonEmpty::try_new(Vec::<i32>::new()).is_none());
let ne = NonEmpty::try_new(vec![1, 2, 3]).unwrap();
assert_eq!(*ne.head(), 1);
assert_eq!(ne.len(), 3);
}
#[test]
fn non_empty_from_parts() {
let ne = NonEmpty::from_parts(10, vec![20, 30]);
assert_eq!(*ne.head(), 10);
assert_eq!(ne.as_slice(), &[10, 20, 30]);
}
#[test]
fn non_empty_singleton() {
let ne = NonEmpty::singleton(42);
assert_eq!(*ne.head(), 42);
assert_eq!(ne.len(), 1);
}
#[test]
fn non_empty_push() {
let mut ne = NonEmpty::singleton(1);
ne.push(2);
assert_eq!(ne.len(), 2);
assert_eq!(ne.as_slice(), &[1, 2]);
}
#[test]
fn non_empty_map() {
let ne = NonEmpty::from_parts(1, vec![2, 3]);
let doubled = ne.map(|x| x * 2);
assert_eq!(doubled.as_slice(), &[2, 4, 6]);
}
#[test]
fn non_empty_into_vec() {
let ne = NonEmpty::from_parts(1, vec![2]);
assert_eq!(ne.into_vec(), vec![1, 2]);
}
#[test]
fn non_empty_iter() {
let ne = NonEmpty::from_parts(1, vec![2, 3]);
let sum: i32 = ne.iter().sum();
assert_eq!(sum, 6);
}
#[test]
fn non_empty_semigroup() {
let a = NonEmpty::from_parts(1, vec![2]);
let b = NonEmpty::from_parts(3, vec![4]);
let c = a.combine(b);
assert_eq!(c.as_slice(), &[1, 2, 3, 4]);
}
#[test]
fn positive_f64() {
assert!(Positive::<f64>::try_new(0.0).is_none());
assert!(Positive::<f64>::try_new(-1.0).is_none());
assert!(Positive::<f64>::try_new(f64::NAN).is_none());
assert!(Positive::<f64>::try_new(f64::INFINITY).is_none());
let p = Positive::<f64>::try_new(4.0).unwrap();
assert_eq!(p.get(), 4.0);
let r = p.reciprocal();
assert!((r.get() - 0.25).abs() < 1e-10);
}
#[test]
fn positive_f32() {
let p = Positive::<f32>::try_new(2.0).unwrap();
assert!((p.reciprocal().get() - 0.5).abs() < 1e-6);
}
#[test]
fn positive_i32() {
assert!(Positive::<i32>::try_new(0).is_none());
assert!(Positive::<i32>::try_new(-5).is_none());
let p = Positive::<i32>::try_new(7).unwrap();
assert_eq!(p.get(), 7);
}
#[test]
fn positive_u32() {
assert!(Positive::<u32>::try_new(0).is_none());
let p = Positive::<u32>::try_new(10).unwrap();
assert_eq!(p.get(), 10);
}
#[test]
fn positive_u32_from_nonzero() {
assert!(Positive::<u32>::from_nonzero(0).is_none());
let p = Positive::<u32>::from_nonzero(5).unwrap();
assert_eq!(p.get(), 5);
}
}