1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//! This is an implementation of the [BigBit standard][BigBitStd], used for representing arbitrarily large numbers and strings in a compact way. The only implementation provided by the author is [a Node.js implementation](https://github.com/bigbit/bigbitjs "BigBit.js on GitHub") — this crate aims to implement the functionality presented there with idiomatic Rust code.
//!
//! In short, the specification describes 3 formats:
//! - **Head Byte** (***HB***), used for storing extremely large (but still finitely large) signed integers *and* decimal fractions without losing precision
//! - **Extended Head Byte** (***EHB***), used for storing arbitrarily large signed integers *and* decimal fractions without losing precision as long as sufficent storage space is provided.
//! - **Linked Bytes** (***LB***), used for storing arbitrarily large **unsigned integers**, mainly used directly inside the Extended Head Byte format to store the exponent and the number of additional coefficient bytes, but also useful for storing strings better than both UTF-8 and UTF-16.
//!
//! Since this is a format parser, `#![no_std]` is enabled by default, meaning that `alloc` is the only dependency, allowing you to use this in a freestanding environment.
//!
//! # State
//! Currently, not the entire BigBit standard is implemented, and **the crate is not ready for use in production just yet**. There are also **no stability guarantees whatsoever**. Here's a list of what's already done:
//! - Head Byte number storage (not really finished, just a stub)
//! - Linked Bytes number storage and arithmetic
//! - Converting Linked Bytes to and from primitive integers
//! - Displaying Linked Bytes numbers in binary, octal, decimal and hexadecimal using formatters as well as other bases (arbitrary from 2 to 36) using a dedicated method
//! - Borrowed Linked Bytes (required for EHB) — a Linked Bytes number which doesn't own its contents and is a slice into an EHB number (still a stub)
//!
//! And here's a list of what's not finished just yet:
//! - Creating \[E\]HB numbers from primitive integers and `f32`/`f64` (most likely will be added in 0.1.0)
//! - The Extended Header Byte format (will be added in 0.0.x)
//! - Arithmetic operations (addition, subtraction, multiplication and division are all defined by the BigBit standard) for \[E\]HB; the main issue is dealing with the exponents (will mark the 1.0.0 release, might be partially added over the course of 0.x.x releases)
//! - Strings encoded using Linked Bytes (will be added in 0.0.x)
//! - `Debug` and `Display` formatting for \[E\]HB (i.e. converting the numbers either into a debugging-friendly representation as an array of bytes or a string representing the number in decimal scientific notation or full notation, as well as other numeric notations; simple `Debug` and `Display` decimal formatting will be added in 0.1.0 while the rest is planned for 1.0.0)
//! - **Tests** (planned for 0.1.0 but might be partially added earlier)
//!
//! # Changelog
//! ## 0.0.6
//! - Added `LBString`, which is an owned string type implementing the Linked Bytes Unicode encoding, allowing for efficient storage of Unicode strings which is under all circumstances more compact than all current UTF encodings
//! - Added `LBNumRef` addition, which was missing due to a copypasting mistake
//! ## 0.0.5
//! - Implemented arithmetic with `self` as the right operand for Linked Bytes, removing the need to always explicitly write `op1 + &op2` (same for other operators)
//! - Fixed the Crates.io badge to link to `bigbit` instead of `bi`**`t`**`bit`
//! - Added `usize` to the list of primitive integer types for which Linked Bytes arithmetic is implemented
//! - Added the `DivRem` and `DivRemAssign` traits for combined division (one operation to get the quotient and remainder)
//! - Renamed `HeadByte::from_headbyte_and_followup` into `from_raw_parts` ***(breaking)***
//! - Implemented logarithm with arbitrary base for Linked Bytes
//! - Implemented string formatting for Linked Bytes
//!
//! ## 0.0.4
//! - Implemented Linked Bytes multiplication and division
//! - Implemented Linked Bytes arithmetic with primitive integers
//! - Reorganized the internal module structure
//! - Added `LBNumRef`
//! - Implemented some more traits on `LBNum`
//!
//! ## 0.0.3
//! - Implemented Linked Bytes subtraction
//! - Started the reorganization
//! - Fixed addition bugs
//!
//!
//! If you're wondering why all versions until `0.0.3` are yanked, these had a minor LB addition bug, so please upgrade if you haven't already.
//!
//! [BigBitStd]: https://github.com/amitguptagwl/BigBit "BitBit specification on GitHub"

#![cfg_attr(feature="clippy", allow(clippy::suspicious_op_assign_impl))] // Fuck this lint, seriously. Whoever wrote "None" in known problems is fucking retarded.

#![no_std]
extern crate alloc;

pub mod headbyte;
pub use headbyte::{HBNum, HeadByte};
// Uncomment these after adding EHB:
//pub mod extheadbyte;
//pub use extheadbyte::{EHBNum, ExtHeadByte};
pub mod linkedbytes;
pub use linkedbytes::{LBNum, LBNumRef, LBString, LBSequence, LinkedByte};

// This module is dedicated to the implementations of `Ord`, `Eq` and arithmetic operations on the BigBit formats. Please implement these there and only there.
mod ops;
mod traits;
pub use traits::*;
pub(crate) mod tables; pub(crate) use tables::*;

/// Combined division and remainder operations.
///
/// The usual process for getting both the division result and the remainder is performing both operations sequentially, since most programming languages, including Rust, do not provide an interface for introspecting the remainder acquired after dividing with the designated CPU instructions (LLVM will, however, optimize the two operations into one, given that optimizations are actually enabled). With BitBit numbers, however, division is implemented iteratively, without harware acceleration, i.e. the CPU doesn't assist the process by providing special instructions to perform the operations.
///
/// The current division implementation simply drops the remainder, which has the cost of deallocating the coefficient/`LinkedByte` sequence, only to allocate and calculate it yet again. By using this trait, you ensure that nothing is ever dropped during division and that you get both the quotient and remainder the fastest way possible.
pub trait DivRem<Rhs = Self>: Sized {
    /// The type for the quotient.
    type Quotient;
    /// The type for the remainder.
    type Remainder;
    /// Performs combined quotient and remainder calculation.
    ///
    /// The first element is the quotient, and the second one is the remainder.
    fn div_rem(self, rhs: Rhs) -> (Self::Quotient, Self::Remainder);
}
/// Division in place combined with retreiving the remainder.
///
/// This serves the same purpose as the [`DivRem`][dr] trait, but the division is performed in place (the variable/field containing the dividend is replaced by the quotient), and the only value returned is the remainder.
///
/// [dr]: trait.DivRem.html "DivRem — combined division and remainder operations"
pub trait DivRemAssign<Rhs = Self> {
    /// The type for the remainder.
    type Remainder;
    /// Performs combined quotient and remainder calculation, returning the remainder and setting the left operand to the quotient.
    fn div_rem_assign(&mut self, rhs: Rhs) -> Self::Remainder;
}

/// The sign of a number.
///
/// Either positive or negative. Zero values in BigBit formats are **always positive**, and `NaN` values are **always negative**.
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Sign {
    Positive = 0,
    Negative = 1
}
impl From<bool> for Sign {
    /// Treats `true` as negative and `false` as positive.
    #[inline]
    #[must_use]
    fn from(op: bool) -> Self {
        if op {Self::Negative} else {Self::Positive}
    }
}
impl From<Sign> for bool {
    /// Treats `true` as negative and `false` as positive.
    #[inline(always)]
    #[must_use]
    fn from(op: Sign) -> Self {
        match op {
            Sign::Positive => false,
            Sign::Negative => true
        }
    }
}
impl core::fmt::Display for Sign {
    fn fmt(&self, fmt: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
        fmt.write_str(match self {
            Sign::Positive => "Positive",
            Sign::Negative => "Negative"
        })
    }
}

/// This is a hack to get around the fact that `debug_struct` only accepts `Debug` formatting rather than `Display`, which becomes a verbosity issue if the values of an enum are known from the name of the field.
#[derive(Copy, Clone, PartialEq, Eq)]
pub(crate) struct SignDisplayAsDebug(pub(crate) Sign);
impl core::fmt::Debug for SignDisplayAsDebug {
    fn fmt(&self, fmt: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
        core::fmt::Display::fmt(&self.0, fmt)
    }
}

#[cfg(test)]
mod tests;