use std::{fmt::Debug,
hash::Hash,
ops::{Add, AddAssign, Deref, DerefMut, Div, Sub, SubAssign}};
use super::{idx, ChUnit, Index};
use crate::ch;
#[derive(Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, Default)]
pub struct Length(pub ChUnit);
pub fn len(arg_length: impl Into<Length>) -> Length { arg_length.into() }
impl Debug for Length {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Length({:?})", self.0)
}
}
mod construct {
use super::{ch, idx, ChUnit, Index, Length};
impl Length {
pub fn new(arg_length: impl Into<Length>) -> Self { arg_length.into() }
#[must_use]
pub fn as_usize(&self) -> usize { self.0.into() }
#[must_use]
pub fn as_u16(&self) -> u16 { self.0.into() }
#[must_use]
pub fn convert_to_index(&self) -> Index {
let it = self.0 - ch(1);
idx(it)
}
}
impl From<ChUnit> for Length {
fn from(ch_unit: ChUnit) -> Self { Length(ch_unit) }
}
impl From<usize> for Length {
fn from(width: usize) -> Self { Length(ch(width)) }
}
impl From<u16> for Length {
fn from(val: u16) -> Self { Length(val.into()) }
}
impl From<i32> for Length {
fn from(val: i32) -> Self { Length(val.into()) }
}
impl From<u8> for Length {
fn from(val: u8) -> Self { Length(val.into()) }
}
}
mod ops {
use super::{Add, AddAssign, ChUnit, Deref, DerefMut, Div, Length, Sub, SubAssign};
impl Deref for Length {
type Target = ChUnit;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl DerefMut for Length {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}
impl Add<Length> for Length {
type Output = Length;
fn add(self, rhs: Length) -> Self::Output { Length(self.0 + rhs.0) }
}
impl AddAssign<Length> for Length {
fn add_assign(&mut self, rhs: Length) { *self = *self + rhs; }
}
impl Sub<Length> for Length {
type Output = Length;
fn sub(self, rhs: Length) -> Self::Output { Length(self.0 - rhs.0) }
}
impl SubAssign<Length> for Length {
fn sub_assign(&mut self, rhs: Length) { *self = *self - rhs; }
}
impl Div<Length> for Length {
type Output = Length;
fn div(self, rhs: Length) -> Self::Output { Length(self.0 / rhs.0) }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_length_creation() {
let length1 = Length::new(10);
let length2 = Length::from(20);
assert_eq!(length1.0, ch(10));
assert_eq!(length2.0, ch(20));
}
#[test]
fn test_length_conversion() {
let length = Length::new(10);
let index = length.convert_to_index();
assert_eq!(index.0, ch(9));
}
#[test]
fn test_length_operators() {
let length1 = Length::new(10);
let length2 = Length::new(20);
let length3 = length1 + length2;
assert_eq!(length3.0, ch(30));
let mut length4 = Length::new(10);
length4 += length2;
assert_eq!(length4.0, ch(30));
let length5 = length2 - length1;
assert_eq!(length5.0, ch(10));
let mut length6 = Length::new(20);
length6 -= length1;
assert_eq!(length6.0, ch(10));
let length7 = length2 / length1;
assert_eq!(length7.0, ch(2));
}
#[test]
fn test_length_deref() {
let length = Length::new(10);
let value = *length;
assert_eq!(value, ch(10));
}
#[test]
fn test_length_deref_mut() {
let mut length = Length::new(10);
*length = ch(20);
assert_eq!(length.0, ch(20));
}
#[test]
fn test_length_from_various_types() {
let length1 = Length::from(10_usize);
let length2 = Length::from(20_u16);
let length3 = Length::from(30_i32);
let length4 = Length::from(40_u8);
assert_eq!(length1.0, ch(10));
assert_eq!(length2.0, ch(20));
assert_eq!(length3.0, ch(30));
assert_eq!(length4.0, ch(40));
}
#[test]
fn test_length_partial_eq() {
let length1 = Length::new(10);
let length2 = Length::new(10);
let length3 = Length::new(20);
assert_eq!(length1, length2);
assert_ne!(length1, length3);
}
#[test]
fn test_length_partial_ord() {
let length1 = Length::new(10);
let length2 = Length::new(20);
assert!(length1 < length2);
assert!(length2 > length1);
assert!(length1 <= length2);
assert!(length2 >= length1);
}
#[test]
fn test_len_fn() {
let length1 = len(10);
assert_eq!(length1.0, ch(10));
let length2 = len(Length::new(20));
assert_eq!(length2.0, ch(20));
}
#[test]
fn test_debug_fmt() {
let length = Length::new(10);
assert_eq!(format!("{length:?}"), "Length(10)");
}
#[test]
fn test_length_max_value() {
let max_length = Length::new(u16::MAX);
assert_eq!(max_length.as_u16(), u16::MAX);
}
#[test]
fn test_length_zero() {
let zero_length = Length::new(0);
assert_eq!(zero_length.0, ch(0));
let index = zero_length.convert_to_index();
assert_eq!(index.0, ch(0)); }
#[test]
fn test_length_interop_with_index() {
let length = Length::new(10);
let index = idx(5);
let new_index = index + length;
assert_eq!(new_index, idx(15));
let new_index = idx(20) - length;
assert_eq!(new_index, idx(10));
}
#[test]
fn test_length_arithmetic_edge_cases() {
let max_length = Length::new(u16::MAX - 5);
let small_length = Length::new(5);
let result = max_length + small_length;
assert_eq!(result, Length::new(u16::MAX));
let length = Length::new(5);
let result = length - Length::new(5);
assert_eq!(result, Length::new(0));
let length = Length::new(5);
let result = length - Length::new(10);
assert_eq!(result, Length::new(0));
}
}