use std::{ fmt::{Debug, Display}, marker::PhantomData, ops::{Add, AddAssign, Sub, SubAssign}, }; use text::Point; #[repr(transparent)] pub struct TypedOffset { pub value: usize, _marker: PhantomData, } #[repr(transparent)] pub struct TypedPoint { pub value: Point, _marker: PhantomData, } #[repr(transparent)] pub struct TypedRow { pub value: u32, _marker: PhantomData, } impl TypedOffset { pub fn new(offset: usize) -> Self { Self { value: offset, _marker: PhantomData, } } pub fn saturating_sub(self, n: TypedOffset) -> Self { Self { value: self.value.saturating_sub(n.value), _marker: PhantomData, } } pub fn zero() -> Self { Self::new(0) } pub fn is_zero(&self) -> bool { self.value == 0 } } impl TypedPoint { pub fn new(row: u32, column: u32) -> Self { Self { value: Point::new(row, column), _marker: PhantomData, } } pub fn wrap(point: Point) -> Self { Self { value: point, _marker: PhantomData, } } pub fn row(&self) -> u32 { self.value.row } pub fn column(&self) -> u32 { self.value.column } pub fn zero() -> Self { Self::wrap(Point::zero()) } pub fn is_zero(&self) -> bool { self.value.is_zero() } } impl TypedRow { pub fn new(row: u32) -> Self { Self { value: row, _marker: PhantomData, } } } impl Copy for TypedOffset {} impl Copy for TypedPoint {} impl Copy for TypedRow {} impl Clone for TypedOffset { fn clone(&self) -> Self { *self } } impl Clone for TypedPoint { fn clone(&self) -> Self { *self } } impl Clone for TypedRow { fn clone(&self) -> Self { *self } } impl Default for TypedOffset { fn default() -> Self { Self::new(0) } } impl Default for TypedPoint { fn default() -> Self { Self::wrap(Point::default()) } } impl Default for TypedRow { fn default() -> Self { Self::new(0) } } impl PartialOrd for TypedOffset { fn partial_cmp(&self, other: &Self) -> Option { Some(self.value.cmp(&other.value)) } } impl PartialOrd for TypedPoint { fn partial_cmp(&self, other: &Self) -> Option { Some(self.value.cmp(&other.value)) } } impl PartialOrd for TypedRow { fn partial_cmp(&self, other: &Self) -> Option { Some(self.value.cmp(&other.value)) } } impl Ord for TypedOffset { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.value.cmp(&other.value) } } impl Ord for TypedPoint { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.value.cmp(&other.value) } } impl Ord for TypedRow { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.value.cmp(&other.value) } } impl PartialEq for TypedOffset { fn eq(&self, other: &Self) -> bool { self.value == other.value } } impl PartialEq for TypedPoint { fn eq(&self, other: &Self) -> bool { self.value == other.value } } impl PartialEq for TypedRow { fn eq(&self, other: &Self) -> bool { self.value == other.value } } impl Eq for TypedOffset {} impl Eq for TypedPoint {} impl Eq for TypedRow {} impl Debug for TypedOffset { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}Offset({})", type_name::(), self.value) } } impl Debug for TypedPoint { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "{}Point({}, {})", type_name::(), self.value.row, self.value.column ) } } impl Debug for TypedRow { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}Row({})", type_name::(), self.value) } } impl Display for TypedOffset { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { Display::fmt(&self.value, f) } } impl Display for TypedRow { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { Display::fmt(&self.value, f) } } fn type_name() -> &'static str { std::any::type_name::().split("::").last().unwrap() } impl Add> for TypedOffset { type Output = Self; fn add(self, other: Self) -> Self { TypedOffset::new(self.value + other.value) } } impl Add> for TypedPoint { type Output = Self; fn add(self, other: Self) -> Self { TypedPoint::wrap(self.value + other.value) } } impl Sub> for TypedOffset { type Output = Self; fn sub(self, other: Self) -> Self { TypedOffset::new(self.value - other.value) } } impl Sub> for TypedPoint { type Output = Self; fn sub(self, other: Self) -> Self { TypedPoint::wrap(self.value - other.value) } } impl AddAssign> for TypedOffset { fn add_assign(&mut self, other: Self) { self.value += other.value; } } impl AddAssign> for TypedPoint { fn add_assign(&mut self, other: Self) { self.value += other.value; } } impl SubAssign for TypedOffset { fn sub_assign(&mut self, other: Self) { self.value -= other.value; } } impl SubAssign for TypedRow { fn sub_assign(&mut self, other: Self) { self.value -= other.value; } }