use crate::integer::{IntegerImpl, Sign};
use crate::Integer;
use crate::{Subscript, Superscript};
use core::fmt::{self, Write};
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct VulgarFraction<T> {
pub numerator: T,
pub denominator: T,
}
impl<T> VulgarFraction<T> {
pub const fn new(numerator: T, denominator: T) -> Self {
Self {
numerator,
denominator,
}
}
}
impl<T> From<(T, T)> for VulgarFraction<T> {
fn from((numerator, denominator): (T, T)) -> Self {
VulgarFraction {
numerator,
denominator,
}
}
}
impl<T> From<T> for VulgarFraction<T>
where
T: Integer,
{
fn from(value: T) -> Self {
VulgarFraction::new(value, <T::Impl as IntegerImpl>::ONE.into_public())
}
}
impl<T> fmt::Display for VulgarFraction<T>
where
T: Integer,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (sign, numerator, denominator) =
extract_sign(self.numerator.into_impl(), self.denominator.into_impl(), f);
if let Some(sign) = sign {
f.write_char(sign)?;
}
if let Some(frac) = (!f.alternate())
.then(|| find_single_character_fraction(numerator, denominator))
.flatten()
{
f.write_char(frac)
} else {
write!(f, "{}", Superscript(numerator.into_public()))?;
const FRACTION_SLASH: char = '\u{2044}';
f.write_char(FRACTION_SLASH)?;
write!(f, "{}", Subscript(denominator.into_public()))
}
}
}
fn extract_sign<T>(numerator: T, denominator: T, f: &fmt::Formatter) -> (Option<char>, T, T)
where
T: IntegerImpl,
{
match numerator.sign() * denominator.sign() {
Sign::PositiveOrZero if f.sign_plus() => (Some('+'), numerator.abs(), denominator.abs()),
Sign::Negative if f.sign_plus() => (Some('-'), numerator.abs(), denominator.abs()),
_ => (None, numerator, denominator),
}
}
fn find_single_character_fraction<N>(numerator: N, denominator: N) -> Option<char>
where
N: TryInto<u8>,
{
match (numerator.try_into().ok()?, denominator.try_into().ok()?) {
(1u8, 4u8) => Some('\u{bc}'),
(1u8, 2u8) => Some('\u{bd}'),
(3u8, 4u8) => Some('\u{be}'),
(1u8, 7u8) => Some('\u{2150}'),
(1u8, 9u8) => Some('\u{2151}'),
(1u8, 10u8) => Some('\u{2152}'),
(1u8, 3u8) => Some('\u{2153}'),
(2u8, 3u8) => Some('\u{2154}'),
(1u8, 5u8) => Some('\u{2155}'),
(2u8, 5u8) => Some('\u{2156}'),
(3u8, 5u8) => Some('\u{2157}'),
(4u8, 5u8) => Some('\u{2158}'),
(1u8, 6u8) => Some('\u{2159}'),
(5u8, 6u8) => Some('\u{215a}'),
(1u8, 8u8) => Some('\u{215b}'),
(3u8, 8u8) => Some('\u{215c}'),
(5u8, 8u8) => Some('\u{215d}'),
(7u8, 8u8) => Some('\u{215e}'),
(0u8, 3u8) => Some('\u{2189}'),
_ => None,
}
}