mod constants;
pub use constants::{
BE_U32_0, BE_U32_1, BE_U32_2, BE_U32_MAX, BE_U32_MIN, BE_U32_NEG_1, BE_U32_NEG_2, BE_U8_0, BE_U8_1, BE_U8_2,
BE_U8_MAX, BE_U8_MIN, BE_U8_NEG_1, BE_U8_NEG_2, LE_U32_0, LE_U32_1, LE_U32_2, LE_U32_MAX, LE_U32_MIN, LE_U32_NEG_1,
LE_U32_NEG_2, LE_U8_0, LE_U8_1, LE_U8_2, LE_U8_MAX, LE_U8_MIN, LE_U8_NEG_1, LE_U8_NEG_2,
};
use crate::ternary::bigint::{
binary_representation::{
BinaryRepresentation, U32Repr, U8Repr, BINARY_LEN_IN_U32 as LEN_IN_U32, BINARY_LEN_IN_U8 as LEN_IN_U8,
},
endianness::{BigEndian, LittleEndian},
error::Error,
overflowing_add::OverflowingAdd,
u384, T242, T243, U384,
};
use bee_ternary::Btrit;
use byteorder::{self, ByteOrder};
use std::{
cmp::Ordering,
convert::{TryFrom, TryInto},
fmt,
marker::PhantomData,
ops::{Deref, DerefMut},
};
#[derive(Clone, Copy)]
pub struct I384<E, T> {
pub(crate) inner: T,
_phantom: PhantomData<E>,
}
impl<E, T> Deref for I384<E, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<E, T> DerefMut for I384<E, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl<E, T, D> fmt::Debug for I384<E, T>
where
E: fmt::Debug,
T: BinaryRepresentation<Inner = D>,
D: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("I384")
.field("inner", &self.inner.iter())
.field("_phantom", &self._phantom)
.finish()
}
}
impl_const_functions!(
( I384 ),
{ BigEndian, LittleEndian },
{ U8Repr, U32Repr }
);
impl_constants!(
I384<BigEndian, U8Repr> => [
(zero, BE_U8_0),
(one, BE_U8_1),
(neg_one, BE_U8_NEG_1),
(two, BE_U8_2),
(neg_two, BE_U8_NEG_2),
(max, BE_U8_MAX),
(min, BE_U8_MIN),
],
I384<LittleEndian, U8Repr> => [
(zero, LE_U8_0),
(one, LE_U8_1),
(neg_one, LE_U8_NEG_1),
(two, LE_U8_2),
(neg_two, LE_U8_NEG_2),
(max, LE_U8_MAX),
(min, LE_U8_MIN),
],
I384<BigEndian, U32Repr> => [
(zero, BE_U32_0),
(one, BE_U32_1),
(neg_one, BE_U32_NEG_1),
(two, BE_U32_2),
(neg_two, BE_U32_NEG_2),
(max, BE_U32_MAX),
(min, BE_U32_MIN),
],
I384<LittleEndian, U32Repr> => [
(zero, LE_U32_0),
(one, LE_U32_1),
(neg_one, LE_U32_NEG_1),
(two, LE_U32_2),
(neg_two, LE_U32_NEG_2),
(max, LE_U32_MAX),
(min, LE_U32_MIN),
],
);
macro_rules! impl_default {
( ( $($type:tt)* ), $len:expr ) => {
impl Default for $($type)* {
fn default() -> Self {
Self {
inner: [0; $len],
_phantom: PhantomData,
}
}
}
};
}
impl I384<BigEndian, U8Repr> {
pub fn not_inplace(&mut self) {
for digit in &mut self.inner[..] {
*digit = !*digit;
}
}
}
impl_default!((I384<BigEndian, U8Repr>), LEN_IN_U8);
impl Eq for I384<BigEndian, U8Repr> {}
impl From<I384<BigEndian, U32Repr>> for I384<BigEndian, U8Repr> {
fn from(value: I384<BigEndian, U32Repr>) -> Self {
let mut i384_u8 = Self::zero();
byteorder::BigEndian::write_u32_into(&value.inner, &mut i384_u8.inner);
i384_u8
}
}
impl PartialEq for I384<BigEndian, U8Repr> {
fn eq(&self, other: &Self) -> bool {
let mut are_equal = true;
for (a, b) in self.inner.iter().zip(other.inner.iter()) {
are_equal &= a == b
}
are_equal
}
}
impl PartialOrd for I384<BigEndian, U8Repr> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
use Ordering::*;
let mut zipped_iter = self.inner.iter().zip(other.inner.iter());
const NEGBIT: u8 = 0x80;
const UMAX: u8 = std::u8::MAX;
let numbers_negative = match zipped_iter.next() {
Some((s @ NEGBIT..=UMAX, o @ NEGBIT..=UMAX)) if s > o => return Some(Greater),
Some((s @ NEGBIT..=UMAX, o @ NEGBIT..=UMAX)) if s < o => return Some(Less),
Some((NEGBIT..=UMAX, NEGBIT..=UMAX)) => true,
Some((NEGBIT..=UMAX, _)) => return Some(Less),
Some((_, NEGBIT..=UMAX)) => return Some(Greater),
Some((s, o)) if s > o => return Some(Greater),
Some((s, o)) if s < o => return Some(Less),
Some(_) => false,
None => unreachable!(),
};
for (s, o) in zipped_iter {
match s.cmp(o) {
Ordering::Greater => return if numbers_negative { Some(Less) } else { Some(Greater) },
Ordering::Less => return if numbers_negative { Some(Greater) } else { Some(Less) },
Ordering::Equal => continue,
}
}
Some(Equal)
}
}
impl Ord for I384<BigEndian, U8Repr> {
fn cmp(&self, other: &Self) -> Ordering {
match self.partial_cmp(other) {
Some(ordering) => ordering,
None => unreachable!(),
}
}
}
impl From<T242<Btrit>> for I384<BigEndian, U8Repr> {
fn from(value: T242<Btrit>) -> Self {
let i384_le: I384<LittleEndian, U32Repr> = value.into();
let i384_be: I384<BigEndian, U32Repr> = i384_le.into();
i384_be.into()
}
}
impl TryFrom<T243<Btrit>> for I384<BigEndian, U8Repr> {
type Error = Error;
fn try_from(value: T243<Btrit>) -> Result<Self, Error> {
let i384_le: I384<LittleEndian, U32Repr> = value.try_into()?;
let i384_be: I384<BigEndian, U32Repr> = i384_le.into();
Ok(i384_be.into())
}
}
impl I384<BigEndian, U32Repr> {
pub fn add_inplace(&mut self, other: Self) {
let mut overflown = false;
let self_iter = self.inner.iter_mut().rev();
let other_iter = other.inner.iter().rev();
for (s, o) in self_iter.zip(other_iter) {
let (sum, still_overflown) = s.overflowing_add_with_carry(*o, overflown as u32);
*s = sum;
overflown = still_overflown;
}
}
pub fn add_digit_inplace<T: Into<u32>>(&mut self, other: T) -> usize {
let other = other.into();
let mut i = self.inner.len() - 1;
let (sum, mut overflown) = self.inner[i].overflowing_add(other);
self.inner[i] = sum;
i -= 1;
while overflown {
let (sum, still_overflown) = self.inner[i].overflowing_add(1u32);
self.inner[i] = sum;
overflown = still_overflown;
i -= 1;
}
i
}
pub fn as_u384(self) -> U384<BigEndian, U32Repr> {
U384::<BigEndian, U32Repr>::from_array(self.inner)
}
pub fn from_t242(value: T242<Btrit>) -> Self {
let t242_unbalanced = value.into_shifted();
let t243_unbalanced = t242_unbalanced.into_t243();
let mut u384_integer = U384::<BigEndian, U32Repr>::try_from_t243(t243_unbalanced).unwrap();
u384_integer.sub_inplace(*u384::BE_U32_HALF_MAX_T242);
u384_integer.as_i384()
}
pub fn is_positive(&self) -> bool {
(self.inner[LEN_IN_U32 - 1] & 0x8000_0000) == 0x0000_0000
}
pub fn is_negative(&self) -> bool {
(self.inner[LEN_IN_U32 - 1] & 0x8000_0000) == 0x8000_0000
}
pub fn not_inplace(&mut self) {
for i in self.inner.iter_mut() {
*i = !*i;
}
}
pub fn shift_into_u384(self) -> U384<BigEndian, U32Repr> {
let mut u384_value = self.as_u384();
u384_value.sub_inplace(*u384::BE_U32_HALF_MAX);
u384_value.sub_inplace(U384::<BigEndian, U32Repr>::one());
u384_value
}
pub fn sub_inplace(&mut self, other: Self) {
let mut borrow = true;
for (s, o) in self.inner.iter_mut().rev().zip(other.inner.iter().rev()) {
let (sum, has_overflown) = s.overflowing_add_with_carry(!*o, borrow as u32);
*s = sum;
borrow = has_overflown;
}
}
pub fn sub_integer_inplace<T: Into<u32>>(&mut self, other: T) -> usize {
let other = other.into();
let (sum, mut overflown) = self.inner[0].overflowing_sub(other);
self.inner[0] = sum;
let mut i = self.inner.len() - 1;
while overflown {
let (sum, still_overflown) = self.inner[i].overflowing_sub(1u32);
self.inner[i] = sum;
overflown = still_overflown;
i -= 1;
}
i
}
pub fn try_from_t243(balanced_trits: T243<Btrit>) -> Result<Self, Error> {
let unbalanced_trits = balanced_trits.into_shifted();
let u384_integer = U384::<BigEndian, U32Repr>::try_from_t243(unbalanced_trits)?;
Ok(u384_integer.shift_into_i384())
}
}
impl_default!((I384<BigEndian, U32Repr>), LEN_IN_U32);
impl Eq for I384<BigEndian, U32Repr> {}
impl From<I384<BigEndian, U8Repr>> for I384<BigEndian, U32Repr> {
fn from(value: I384<BigEndian, U8Repr>) -> Self {
let mut i384_u32 = Self::zero();
byteorder::BigEndian::read_u32_into(&value.inner, &mut i384_u32.inner);
i384_u32
}
}
impl Ord for I384<BigEndian, U32Repr> {
fn cmp(&self, other: &Self) -> Ordering {
match self.partial_cmp(other) {
Some(ordering) => ordering,
None => unreachable!(),
}
}
}
impl PartialEq for I384<BigEndian, U32Repr> {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
impl PartialOrd for I384<BigEndian, U32Repr> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
use Ordering::*;
let mut zipped_iter = self.inner.iter().zip(other.inner.iter());
const NEGBIT: u32 = 0x8000_0000;
const UMAX: u32 = std::u32::MAX;
let numbers_negative = match zipped_iter.next() {
Some((s @ NEGBIT..=UMAX, o @ NEGBIT..=UMAX)) if s > o => return Some(Greater),
Some((s @ NEGBIT..=UMAX, o @ NEGBIT..=UMAX)) if s < o => return Some(Less),
Some((NEGBIT..=UMAX, NEGBIT..=UMAX)) => true,
Some((NEGBIT..=UMAX, _)) => return Some(Less),
Some((_, NEGBIT..=UMAX)) => return Some(Greater),
Some((s, o)) if s > o => return Some(Greater),
Some((s, o)) if s < o => return Some(Less),
Some(_) => false,
None => unreachable!(),
};
for (s, o) in zipped_iter {
match s.cmp(o) {
Ordering::Greater => return if numbers_negative { Some(Less) } else { Some(Greater) },
Ordering::Less => return if numbers_negative { Some(Greater) } else { Some(Less) },
Ordering::Equal => continue,
}
}
Some(Equal)
}
}
impl From<T242<Btrit>> for I384<BigEndian, U32Repr> {
fn from(value: T242<Btrit>) -> Self {
let i384_le: I384<LittleEndian, U32Repr> = value.into();
i384_le.into()
}
}
impl TryFrom<T243<Btrit>> for I384<BigEndian, U32Repr> {
type Error = Error;
fn try_from(value: T243<Btrit>) -> Result<Self, Error> {
let i384_le: I384<LittleEndian, U32Repr> = value.try_into()?;
Ok(i384_le.into())
}
}
impl_default!((I384<LittleEndian, U8Repr>), LEN_IN_U8);
impl Eq for I384<LittleEndian, U8Repr> {}
impl From<I384<LittleEndian, U32Repr>> for I384<LittleEndian, U8Repr> {
fn from(value: I384<LittleEndian, U32Repr>) -> Self {
let mut i384_u8 = Self::zero();
byteorder::LittleEndian::write_u32_into(&value.inner, &mut i384_u8.inner);
i384_u8
}
}
impl Ord for I384<LittleEndian, U8Repr> {
fn cmp(&self, other: &Self) -> Ordering {
match self.partial_cmp(other) {
Some(ordering) => ordering,
None => unreachable!(),
}
}
}
impl PartialEq for I384<LittleEndian, U8Repr> {
fn eq(&self, other: &Self) -> bool {
let mut are_equal = true;
for (a, b) in self.inner.iter().zip(other.inner.iter()) {
are_equal &= a == b
}
are_equal
}
}
impl PartialOrd for I384<LittleEndian, U8Repr> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
use Ordering::*;
let mut zipped_iter = self.inner.iter().rev().zip(other.inner.iter().rev());
const NEGBIT: u8 = 0x80;
const UMAX: u8 = std::u8::MAX;
let numbers_negative = match zipped_iter.next() {
Some((s @ NEGBIT..=UMAX, o @ NEGBIT..=UMAX)) if s > o => return Some(Greater),
Some((s @ NEGBIT..=UMAX, o @ NEGBIT..=UMAX)) if s < o => return Some(Less),
Some((NEGBIT..=UMAX, NEGBIT..=UMAX)) => true,
Some((NEGBIT..=UMAX, _)) => return Some(Less),
Some((_, NEGBIT..=UMAX)) => return Some(Greater),
Some((s, o)) if s > o => return Some(Greater),
Some((s, o)) if s < o => return Some(Less),
Some(_) => false,
None => unreachable!(),
};
for (s, o) in zipped_iter {
match s.cmp(o) {
Ordering::Greater => return if numbers_negative { Some(Less) } else { Some(Greater) },
Ordering::Less => return if numbers_negative { Some(Greater) } else { Some(Less) },
Ordering::Equal => continue,
}
}
Some(Equal)
}
}
impl I384<LittleEndian, U32Repr> {
pub fn add_inplace(&mut self, other: Self) {
let mut overflown = false;
let self_iter = self.inner.iter_mut();
let other_iter = other.inner.iter();
for (s, o) in self_iter.zip(other_iter) {
let (sum, still_overflown) = s.overflowing_add_with_carry(*o, overflown as u32);
*s = sum;
overflown = still_overflown;
}
}
pub fn add_digit_inplace<T: Into<u32>>(&mut self, other: T) -> usize {
let other = other.into();
let (sum, mut overflown) = self.inner[0].overflowing_add(other);
self.inner[0] = sum;
let mut i = 1;
while overflown {
let (sum, still_overflown) = self.inner[i].overflowing_add(1u32);
self.inner[i] = sum;
overflown = still_overflown;
i += 1;
}
i
}
pub fn as_u384(self) -> U384<LittleEndian, U32Repr> {
U384::<LittleEndian, U32Repr>::from_array(self.inner)
}
pub fn from_t242(value: T242<Btrit>) -> Self {
let t242_unbalanced = value.into_shifted();
let t243_unbalanced = t242_unbalanced.into_t243();
let mut u384_integer = U384::<LittleEndian, U32Repr>::try_from_t243(t243_unbalanced).unwrap();
u384_integer.sub_inplace(*u384::LE_U32_HALF_MAX_T242);
u384_integer.as_i384()
}
pub fn is_positive(&self) -> bool {
(self.inner[LEN_IN_U32 - 1] & 0x8000_0000) == 0x0000_0000
}
pub fn is_negative(&self) -> bool {
(self.inner[LEN_IN_U32 - 1] & 0x8000_0000) == 0x8000_0000
}
pub fn not_inplace(&mut self) {
for i in self.inner.iter_mut() {
*i = !*i;
}
}
pub fn shift_into_u384(self) -> U384<LittleEndian, U32Repr> {
let mut u384_value = self.as_u384();
u384_value.sub_inplace(*u384::LE_U32_HALF_MAX);
u384_value.sub_inplace(U384::<LittleEndian, U32Repr>::one());
u384_value
}
pub fn sub_inplace(&mut self, other: Self) {
let self_iter = self.inner.iter_mut();
let other_iter = other.inner.iter();
let mut borrow = true;
for (s, o) in self_iter.zip(other_iter) {
let (sum, has_overflown) = s.overflowing_add_with_carry(!*o, borrow as u32);
*s = sum;
borrow = has_overflown;
}
}
pub fn sub_integer_inplace<T: Into<u32>>(&mut self, other: T) -> usize {
let other = other.into();
let (sum, mut overflown) = self.inner[0].overflowing_sub(other);
self.inner[0] = sum;
let mut i = 1;
while overflown {
let (sum, still_overflown) = self.inner[i].overflowing_sub(1u32);
self.inner[i] = sum;
overflown = still_overflown;
i += 1;
}
i
}
pub fn try_from_t243(balanced_trits: T243<Btrit>) -> Result<Self, Error> {
let unbalanced_trits = balanced_trits.into_shifted();
let u384_integer = U384::<LittleEndian, U32Repr>::try_from_t243(unbalanced_trits)?;
Ok(u384_integer.shift_into_i384())
}
pub fn zero_most_significant_trit(&mut self) {
if *self > u384::LE_U32_HALF_MAX_T242.as_i384() {
self.sub_inplace(u384::LE_U32_ONLY_T243_OCCUPIED.as_i384());
} else if *self < u384::LE_U32_NEG_HALF_MAX_T242.as_i384() {
self.add_inplace(u384::LE_U32_ONLY_T243_OCCUPIED.as_i384());
}
}
}
impl_default!((I384<LittleEndian, U32Repr>), LEN_IN_U32);
impl Eq for I384<LittleEndian, U32Repr> {}
impl From<I384<LittleEndian, U8Repr>> for I384<LittleEndian, U32Repr> {
fn from(value: I384<LittleEndian, U8Repr>) -> Self {
let mut i384_u32 = I384::<LittleEndian, U32Repr>::zero();
byteorder::LittleEndian::read_u32_into(&value.inner, &mut i384_u32.inner);
i384_u32
}
}
impl Ord for I384<LittleEndian, U32Repr> {
fn cmp(&self, other: &Self) -> Ordering {
match self.partial_cmp(other) {
Some(ordering) => ordering,
None => unreachable!(),
}
}
}
impl PartialEq for I384<LittleEndian, U32Repr> {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
impl PartialOrd for I384<LittleEndian, U32Repr> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
use Ordering::*;
let mut zipped_iter = self.inner.iter().rev().zip(other.inner.iter().rev());
const NEGBIT: u32 = 0x8000_0000;
const UMAX: u32 = std::u32::MAX;
let numbers_negative = match zipped_iter.next() {
Some((s @ NEGBIT..=UMAX, o @ NEGBIT..=UMAX)) if s > o => return Some(Greater),
Some((s @ NEGBIT..=UMAX, o @ NEGBIT..=UMAX)) if s < o => return Some(Less),
Some((NEGBIT..=UMAX, NEGBIT..=UMAX)) => true,
Some((NEGBIT..=UMAX, _)) => return Some(Less),
Some((_, NEGBIT..=UMAX)) => return Some(Greater),
Some((s, o)) if s > o => return Some(Greater),
Some((s, o)) if s < o => return Some(Less),
Some(_) => false,
None => unreachable!(),
};
for (s, o) in zipped_iter {
match s.cmp(o) {
Ordering::Greater => return if numbers_negative { Some(Less) } else { Some(Greater) },
Ordering::Less => return if numbers_negative { Some(Greater) } else { Some(Less) },
Ordering::Equal => continue,
}
}
Some(Equal)
}
}
impl From<T242<Btrit>> for I384<LittleEndian, U32Repr> {
fn from(value: T242<Btrit>) -> Self {
Self::from_t242(value)
}
}
impl TryFrom<T243<Btrit>> for I384<LittleEndian, U32Repr> {
type Error = Error;
fn try_from(value: T243<Btrit>) -> Result<Self, Error> {
Self::try_from_t243(value)
}
}
impl_toggle_endianness!((I384), U8Repr, U32Repr);