use std::{fmt::Debug,
hash::Hash,
ops::{Add, AddAssign, Deref, DerefMut, Mul, Sub, SubAssign}};
use super::{ChUnit, Length};
use crate::ch;
#[derive(Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, Default)]
pub struct Index(pub ChUnit);
pub fn idx(arg_index: impl Into<Index>) -> Index { arg_index.into() }
impl Debug for Index {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Index({:?})", self.0)
}
}
mod construct {
use super::{ch, ChUnit, Index, Length};
impl Index {
pub fn new(arg_col_index: impl Into<Index>) -> Self { arg_col_index.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_length(&self) -> Length { Length(self.0 + ch(1)) }
}
impl From<ChUnit> for Index {
fn from(ch_unit: ChUnit) -> Self { Index(ch_unit) }
}
impl From<usize> for Index {
fn from(val: usize) -> Self { Index(val.into()) }
}
impl From<Index> for usize {
fn from(col: Index) -> Self { col.as_usize() }
}
impl From<u16> for Index {
fn from(val: u16) -> Self { Index(val.into()) }
}
impl From<i32> for Index {
fn from(val: i32) -> Self { Index(val.into()) }
}
}
mod ops {
use super::{Add, AddAssign, ChUnit, Deref, DerefMut, Index, Length, Mul, Sub,
SubAssign};
impl Deref for Index {
type Target = ChUnit;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl DerefMut for Index {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}
impl Add<Index> for Index {
type Output = Index;
fn add(self, rhs: Index) -> Self::Output {
let mut self_copy = self;
self_copy.0 += rhs.0;
self_copy
}
}
impl AddAssign for Index {
fn add_assign(&mut self, rhs: Self) { self.0 += rhs.0; }
}
impl Sub<Index> for Index {
type Output = Index;
fn sub(self, rhs: Index) -> Self::Output {
let mut self_copy = self;
self_copy.0 -= rhs.0;
self_copy
}
}
impl SubAssign<Index> for Index {
fn sub_assign(&mut self, rhs: Index) { self.0 -= rhs.0; }
}
impl Sub<Length> for Index {
type Output = Index;
fn sub(self, rhs: Length) -> Self::Output {
let mut self_copy = self;
self_copy.0 -= rhs.0;
self_copy
}
}
impl SubAssign<Length> for Index {
fn sub_assign(&mut self, rhs: Length) { self.0 -= rhs.0; }
}
impl Add<Length> for Index {
type Output = Index;
fn add(self, rhs: Length) -> Self::Output {
let mut self_copy = self;
self_copy.0 += rhs.0;
self_copy
}
}
impl AddAssign<Length> for Index {
fn add_assign(&mut self, rhs: Length) { self.0 += rhs.0; }
}
impl Mul<Length> for Index {
type Output = Index;
fn mul(self, rhs: Length) -> Self::Output {
let mut self_copy = self;
self_copy.0 *= rhs.0;
self_copy
}
}
}
#[cfg(test)]
mod tests {
use std::hash::{DefaultHasher, Hasher};
use super::*;
use crate::{len, BoundsCheck, BoundsStatus};
#[test]
fn test_index_new() {
let index = Index::new(10);
assert_eq!(index, idx(10));
}
#[test]
fn test_index_add() {
let index1 = idx(10);
let index2 = idx(5);
let result = index1 + index2;
assert_eq!(result, idx(15));
}
#[test]
fn test_index_add_assign() {
let mut index1 = idx(10);
let index2 = idx(5);
index1 += index2;
assert_eq!(index1, idx(15));
}
#[test]
fn test_index_sub() {
let index1 = idx(10);
let index2 = idx(5);
let result = index1 - index2;
assert_eq!(result, idx(5));
}
#[test]
fn test_index_sub_assign() {
let mut index1 = idx(10);
let index2 = idx(5);
index1 -= index2;
assert_eq!(index1, idx(5));
}
#[test]
fn test_index_from_ch_unit() {
let ch_unit = ch(10);
let index = Index::from(ch_unit);
assert_eq!(index, idx(10));
}
#[test]
fn test_index_from_usize() {
let val = 10_usize;
let index = Index::from(val);
assert_eq!(index, idx(10));
}
#[test]
fn test_index_from_u16() {
let val = 10_u16;
let index = Index::from(val);
assert_eq!(index, idx(10));
}
#[test]
fn test_index_from_i32() {
let val = 10_i32;
let index = Index::from(val);
assert_eq!(index, idx(10));
}
#[test]
fn test_index_as_usize() {
let index = idx(10);
let val = index.as_usize();
assert_eq!(val, 10_usize);
}
#[test]
fn test_index_as_u16() {
let index = idx(10);
let val = index.as_u16();
assert_eq!(val, 10_u16);
}
#[test]
fn test_index_convert_to_length() {
let index = idx(9); let value = index.convert_to_length(); assert_eq!(value, len(10));
}
#[test]
fn test_index_deref() {
let index = idx(10);
let value = *index;
assert_eq!(value, ch(10));
}
#[test]
fn test_index_deref_mut() {
let mut index = idx(10);
*index = ch(20);
assert_eq!(index, idx(20));
}
#[test]
fn test_index_sub_length() {
let index = idx(10);
let length = len(3);
let result = index - length;
assert_eq!(result, idx(7));
}
#[test]
fn test_index_sub_assign_length() {
let mut index = idx(10);
let length = len(3);
index -= length;
assert_eq!(index, idx(7));
}
#[test]
fn test_index_add_length() {
let index = idx(10);
let length = len(3);
let result = index + length;
assert_eq!(result, idx(13));
}
#[test]
fn test_index_add_assign_length() {
let mut index = idx(10);
let length = len(3);
index += length;
assert_eq!(index, idx(13));
}
#[test]
fn test_index_mul_length() {
let index = idx(10);
let length = len(3);
let result = index * length;
assert_eq!(result, idx(30));
}
#[test]
fn test_index_into_usize() {
let index = idx(10);
let result: usize = index.into();
assert_eq!(result, 10);
}
#[test]
fn test_index_debug_fmt() {
let index = idx(10);
let debug_string = format!("{index:?}");
assert_eq!(debug_string, "Index(10)");
}
#[test]
fn test_index_partial_ord() {
let index1 = idx(10);
let index2 = idx(5);
assert!(index1 > index2);
assert!(index2 < index1);
assert!(index1 >= index2);
assert!(index2 <= index1);
}
#[test]
fn test_index_ord() {
let index1 = idx(10);
let index2 = idx(5);
assert!(index1 > index2);
assert!(index2 < index1);
}
#[test]
fn test_index_eq() {
let index1 = idx(10);
let index2 = idx(10);
assert_eq!(index1, index2);
}
#[test]
fn test_index_ne() {
let index1 = idx(10);
let index2 = idx(5);
assert_ne!(index1, index2);
}
#[test]
fn test_index_hash() {
let index1 = idx(10);
let index2 = idx(10);
let mut hasher1 = DefaultHasher::new();
index1.hash(&mut hasher1);
let hash1 = hasher1.finish();
let mut hasher2 = DefaultHasher::new();
index2.hash(&mut hasher2);
let hash2 = hasher2.finish();
assert_eq!(hash1, hash2);
}
#[test]
fn test_idx_fn() {
let index = Index(ch(10));
assert_eq!(index, idx(10));
}
#[test]
fn test_index_max_value() {
let max_index = idx(u16::MAX);
assert_eq!(max_index.as_u16(), u16::MAX);
}
#[test]
fn test_index_convert_to_length_edge_cases() {
let index = idx(0);
let length = index.convert_to_length();
assert_eq!(length, len(1));
let max_index = idx(u16::MAX - 1); let length = max_index.convert_to_length();
assert_eq!(length, len(u16::MAX));
}
#[test]
fn test_index_arithmetic_edge_cases() {
let max_index = idx(u16::MAX - 5);
let small_index = idx(5);
let result = max_index + small_index;
assert_eq!(result, idx(u16::MAX));
let index = idx(5);
let result = index - idx(5);
assert_eq!(result, idx(0));
let index = idx(5);
let result = index - idx(10);
assert_eq!(result, idx(0));
}
#[test]
fn test_index_with_length_operations_edge_cases() {
let max_index = idx(u16::MAX - 5);
let length = len(5);
let result = max_index + length;
assert_eq!(result, idx(u16::MAX));
let index = idx(10);
let length = len(5);
let result = index - length;
assert_eq!(result, idx(5));
let index = idx(5);
let length = len(10);
let result = index - length;
assert_eq!(result, idx(0));
let index = idx(u16::MAX / 2);
let length = len(2);
let result = index * length;
assert_eq!(result, idx(u16::MAX - 1)); }
#[test]
fn test_index_bounds_check_with_length() {
let index = idx(5);
let length = len(10);
assert_eq!(index.check_overflows(length), BoundsStatus::Within);
let index = idx(9);
let length = len(10);
assert_eq!(index.check_overflows(length), BoundsStatus::Within);
let index = idx(10);
let length = len(10);
assert_eq!(index.check_overflows(length), BoundsStatus::Overflowed);
let index = idx(20);
let length = len(10);
assert_eq!(index.check_overflows(length), BoundsStatus::Overflowed);
}
#[test]
fn test_index_bounds_check_with_index() {
let index1 = idx(5);
let index2 = idx(10);
assert_eq!(index1.check_overflows(index2), BoundsStatus::Within);
let index1 = idx(10);
let index2 = idx(10);
assert_eq!(index1.check_overflows(index2), BoundsStatus::Within);
let index1 = idx(11);
let index2 = idx(10);
assert_eq!(index1.check_overflows(index2), BoundsStatus::Overflowed);
let index1 = idx(20);
let index2 = idx(10);
assert_eq!(index1.check_overflows(index2), BoundsStatus::Overflowed);
}
#[test]
fn test_index_bounds_check_edge_cases() {
let index = idx(0);
let length = len(0);
assert_eq!(index.check_overflows(length), BoundsStatus::Within);
let index = idx(0);
let length = len(0);
assert_eq!(index.check_overflows(length), BoundsStatus::Within);
let index = idx(1);
let length = len(0);
assert_eq!(index.check_overflows(length), BoundsStatus::Overflowed);
let index = idx(u16::MAX);
let length = len(u16::MAX);
assert_eq!(index.check_overflows(length), BoundsStatus::Overflowed);
let index = idx(u16::MAX - 1);
let length = len(u16::MAX);
assert_eq!(index.check_overflows(length), BoundsStatus::Within);
}
#[test]
fn test_full_interoperability() {
let index = idx(5);
let length = len(10);
assert_eq!(index.check_overflows(length), BoundsStatus::Within);
let new_length = index.convert_to_length();
assert_eq!(new_length, len(6));
let new_index = length.convert_to_index();
assert_eq!(new_index, idx(9));
let result_index = index + length;
assert_eq!(result_index, idx(15));
assert_eq!(
result_index.check_overflows(length),
BoundsStatus::Overflowed
);
let result_index = result_index - length;
assert_eq!(result_index, idx(5));
assert_eq!(result_index.check_overflows(length), BoundsStatus::Within);
}
}