use crate::concepts::DigitOperate;
use crate::{Digit, Ternary};
use alloc::string::ToString;
use alloc::vec::Vec;
use core::fmt::Display;
use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Sub};
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[repr(transparent)]
pub struct TritsChunk(i8);
impl TritsChunk {
pub fn from_dec(from: i8) -> Self {
if !(-121..=121).contains(&from) {
panic!("TritsChunk::from_dec(): Invalid value: {}", from);
}
Self(from)
}
pub fn to_dec(&self) -> i8 {
self.0
}
pub fn to_ternary(&self) -> Ternary {
Ternary::from_dec(self.0 as i64)
}
pub fn to_fixed_ternary(&self) -> Ternary {
Ternary::from_dec(self.0 as i64).with_length(5)
}
pub fn to_digits(&self) -> Vec<Digit> {
self.to_fixed_ternary().to_digit_slice().to_vec()
}
pub fn from_ternary(ternary: Ternary) -> Self {
if ternary.log() > 5 {
panic!(
"TritsChunk::from_ternary(): Ternary is too long: {}",
ternary.to_string()
);
}
Self(ternary.to_dec() as i8)
}
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct DataTernary {
chunks: Vec<TritsChunk>,
}
impl DataTernary {
pub fn from_ternary(ternary: Ternary) -> Self {
let len = ternary.log();
let diff = (5 - len % 5) % 5;
let ternary = ternary.with_length(len + diff);
let mut chunks = Vec::new();
for i in 0..(ternary.log() / 5) {
let digits = ternary.to_digit_slice()[i * 5..(i + 1) * 5].to_vec();
chunks.push(TritsChunk::from_ternary(Ternary::new(digits)));
}
Self { chunks }
}
pub fn to_ternary(&self) -> Ternary {
let mut digits = Vec::new();
for chunk in &self.chunks {
digits.extend(chunk.to_ternary().to_digit_slice());
}
Ternary::new(digits).trim()
}
pub fn to_fixed_ternary(&self) -> Ternary {
let mut digits = Vec::new();
for chunk in &self.chunks {
digits.extend(chunk.to_digits());
}
Ternary::new(digits).trim()
}
pub fn to_digits(&self) -> Vec<Digit> {
self.to_ternary().trim().to_digit_slice().to_vec()
}
pub fn from_dec(from: i64) -> Self {
Self::from_ternary(Ternary::from_dec(from))
}
pub fn to_dec(&self) -> i64 {
self.to_ternary().to_dec()
}
}
impl Display for DataTernary {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
for chunk in &self.chunks {
write!(f, "{}", chunk.to_fixed_ternary())?;
}
Ok(())
}
}
impl From<Ternary> for DataTernary {
fn from(value: Ternary) -> Self {
Self::from_ternary(value)
}
}
impl From<DataTernary> for Ternary {
fn from(value: DataTernary) -> Self {
value.to_ternary()
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[repr(transparent)]
pub struct Ter40(i64);
impl Ter40 {
pub fn from_dec(from: i64) -> Self {
Self(from)
}
pub fn to_dec(&self) -> i64 {
self.0
}
pub fn from_ternary(ternary: Ternary) -> Self {
Self(ternary.to_dec())
}
pub fn to_ternary(&self) -> Ternary {
Ternary::from_dec(self.0).with_length(40)
}
}
impl DigitOperate for Ter40 {
fn to_digits(&self) -> Vec<Digit> {
self.to_ternary().to_digits()
}
fn digit(&self, index: usize) -> Option<Digit> {
self.to_ternary().digit(index)
}
fn each(&self, f: impl Fn(Digit) -> Digit) -> Self
where
Self: Sized,
{
Self(self.to_ternary().each(f).to_dec())
}
fn each_with(&self, f: impl Fn(Digit, Digit) -> Digit, other: Digit) -> Self
where
Self: Sized,
{
Self(self.to_ternary().each_with(f, other).to_dec())
}
fn each_zip(&self, f: impl Fn(Digit, Digit) -> Digit, other: Self) -> Self
where
Self: Sized,
{
Self(self.to_ternary().each_zip(f, other.to_ternary()).to_dec())
}
fn each_zip_carry(&self, f: impl Fn(Digit, Digit, Digit) -> (Digit, Digit), other: Self) -> Self
where
Self: Sized,
{
Self(
self.to_ternary()
.each_zip_carry(f, other.to_ternary())
.to_dec(),
)
}
}
impl Display for Ter40 {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.to_ternary())
}
}
impl Add for Ter40 {
type Output = Self;
fn add(self, other: Self) -> Self::Output {
Self(self.0 + other.0)
}
}
impl Sub for Ter40 {
type Output = Self;
fn sub(self, other: Self) -> Self::Output {
Self(self.0 - other.0)
}
}
impl Mul for Ter40 {
type Output = Self;
fn mul(self, other: Self) -> Self::Output {
Self(self.0 * other.0)
}
}
impl Div for Ter40 {
type Output = Self;
fn div(self, other: Self) -> Self::Output {
Self(self.0 / other.0)
}
}
impl Neg for Ter40 {
type Output = Self;
fn neg(self) -> Self::Output {
Self(-self.0)
}
}
impl BitAnd for Ter40 {
type Output = Self;
fn bitand(self, other: Self) -> Self::Output {
self.each_zip(Digit::bitand, other)
}
}
impl BitOr for Ter40 {
type Output = Self;
fn bitor(self, other: Self) -> Self::Output {
self.each_zip(Digit::bitor, other)
}
}
impl BitXor for Ter40 {
type Output = Self;
fn bitxor(self, other: Self) -> Self::Output {
self.each_zip(Digit::bitxor, other)
}
}
impl From<i64> for Ter40 {
fn from(value: i64) -> Self {
Self(value)
}
}
impl From<Ter40> for i64 {
fn from(value: Ter40) -> Self {
value.0
}
}
impl From<Ternary> for Ter40 {
fn from(value: Ternary) -> Self {
Self::from_ternary(value)
}
}
impl From<Ter40> for Ternary {
fn from(value: Ter40) -> Self {
value.to_ternary()
}
}
#[cfg(test)]
#[test]
fn single_chunk_creation() {
use crate::Ternary;
let ternary = Ternary::parse("+-0-+");
let data = DataTernary::from_ternary(ternary.clone());
assert_eq!(data.chunks.len(), 1);
assert_eq!(data.to_ternary(), ternary);
}
#[cfg(test)]
#[test]
fn round_trip() {
use crate::Ternary;
let ternary = Ternary::parse("+0-0++-");
let data = DataTernary::from_ternary(ternary.clone());
assert_eq!(data.to_ternary(), ternary);
}