use std::ops::{Add, Sub};
pub trait CycleAdd<T: Add<Output = T> + Sub<Output = T> + PartialEq + Copy> {
fn cycle_add(&self, other: T, base: T) -> T;
fn cycle_sub(&self, other: T, base: T) -> T;
fn series_add(&self, other: T, limit: T) -> T;
fn series_sub(&self, other: T, limit: T) -> T;
fn series_mod(&self, limit: T) -> T;
}
macro_rules! impl_cycle_add {
($t:ty,$u:ty) => {
impl CycleAdd<$t> for $t {
fn cycle_add(&self, other: $t, base: $t) -> $t {
let b2 = base as $u;
let result: $u = *self as $u + other as $u;
if result < b2 {
result as $t
} else {
(result % base as $u) as $t
}
}
fn cycle_sub(&self, other: $t, base: $t) -> $t {
if *self < other {
let b2 = base as $u;
let result = b2 + *self as $u - other as $u ;
(result % b2) as $t
} else {
*self - (other % base)
}
}
fn series_add(&self, other: $t, limit: $t) -> $t {
let start_val = *self - 1;
let b2 = limit as $u;
let result: $u = start_val as $u + other as $u;
if result < b2 {
result as $t + 1
} else {
(result % limit as $u) as $t + 1
}
}
fn series_sub(&self, other: $t, limit: $t) -> $t {
let start_val = *self - 1;
if start_val < other {
let b2 = limit as $u;
let result = b2 + start_val as $u - other as $u ;
(result % b2) as $t + 1
} else {
start_val - (other % limit) + 1
}
}
fn series_mod(&self, limit: $t) -> $t {
let result = *self % limit;
if result < 1 {
limit
} else {
result
}
}
}
};
}
impl_cycle_add!(u8, u16);
impl_cycle_add!(u16, u32);
impl_cycle_add!(u32, u64);