use std::fmt;
use super::{Format, FormattedValueNoneBuilder};
use crate::utils::Displayable;
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Signed<T> {
Negative(T),
Positive(T),
}
impl<T> Signed<T> {
pub fn is_positive(self) -> bool {
matches!(self, Signed::Positive(_))
}
pub fn positive(self) -> Option<T> {
match self {
Signed::Positive(val) => Some(val),
Signed::Negative(_) => None,
}
}
pub fn positive_or<E>(self, err: E) -> Result<T, E> {
match self {
Signed::Positive(val) => Ok(val),
Signed::Negative(_) => Err(err),
}
}
pub fn positive_or_else<E, F: FnOnce(T) -> E>(self, err: F) -> Result<T, E> {
match self {
Signed::Positive(val) => Ok(val),
Signed::Negative(val) => Err(err(val)),
}
}
pub fn is_negative(self) -> bool {
matches!(self, Signed::Negative(_))
}
pub fn negative(self) -> Option<T> {
match self {
Signed::Negative(val) => Some(val),
Signed::Positive(_) => None,
}
}
pub fn negative_or<E>(self, err: E) -> Result<T, E> {
match self {
Signed::Negative(val) => Ok(val),
Signed::Positive(_) => Err(err),
}
}
pub fn negative_or_else<E, F: FnOnce(T) -> E>(self, err: F) -> Result<T, E> {
match self {
Signed::Negative(val) => Ok(val),
Signed::Positive(val) => Err(err(val)),
}
}
pub fn abs(self) -> T {
match self {
Signed::Positive(val) | Signed::Negative(val) => val,
}
}
}
impl<T> std::ops::Neg for Signed<T> {
type Output = Signed<T>;
fn neg(self) -> Self {
match self {
Signed::Positive(val) => Signed::Negative(val),
Signed::Negative(val) => Signed::Positive(val),
}
}
}
pub trait SignedIntrinsic {}
impl<T> fmt::Display for Signed<T>
where
T: fmt::Display + SignedIntrinsic,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use std::fmt::Write;
let (sign, val) = match self {
Signed::Positive(val) => ('+', val),
Signed::Negative(val) => ('-', val),
};
f.write_char(sign)?;
fmt::Display::fmt(&val, f)
}
}
impl<T> Displayable for Signed<T>
where
T: fmt::Display + SignedIntrinsic,
{
type DisplayImpl = Signed<T>;
fn display(self) -> Self::DisplayImpl {
self
}
}
impl<T> Signed<Option<T>> {
pub fn transpose(self) -> Option<Signed<T>> {
use Signed::*;
match self {
Positive(Some(val)) => Some(Positive(val)),
Negative(Some(val)) => Some(Negative(val)),
_ => None,
}
}
}
pub struct DisplayableOptionSigned<T>(Option<Signed<T>>);
impl<T> fmt::Display for DisplayableOptionSigned<T>
where
T: fmt::Display + SignedIntrinsic,
Option<T>: Displayable,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.0 {
Some(ref signed) => fmt::Display::fmt(signed, f),
None => fmt::Display::fmt(&Option::<T>::None.display(), f),
}
}
}
impl<T> Displayable for Option<Signed<T>>
where
T: fmt::Display + SignedIntrinsic,
Option<T>: Displayable,
{
type DisplayImpl = DisplayableOptionSigned<T>;
fn display(self) -> Self::DisplayImpl {
DisplayableOptionSigned(self)
}
}
impl<T> Displayable for Signed<Option<T>>
where
T: fmt::Display + SignedIntrinsic,
Option<T>: Displayable,
{
type DisplayImpl = DisplayableOptionSigned<T>;
fn display(self) -> Self::DisplayImpl {
DisplayableOptionSigned(self.transpose())
}
}
pub trait UnsignedIntoSigned: Copy + Sized {
type Signed;
fn into_signed(self, sign: i32) -> Self::Signed {
if sign.is_positive() {
self.into_positive()
} else {
self.into_negative()
}
}
fn into_positive(self) -> Self::Signed;
fn into_negative(self) -> Self::Signed;
}
impl_unsigned_int_into_signed!(u64);
impl_signed_ops!(u64);
impl_signed_div_mul!(u64);
impl_unsigned_int_into_signed!(u32);
impl_signed_ops!(u32);
impl_signed_div_mul!(u32);
impl From<i64> for Signed<u64> {
fn from(val: i64) -> Signed<u64> {
skip_assert_initialized!();
match val {
positive if positive.is_positive() => Signed::Positive(positive as u64),
i64::MIN => {
Signed::Negative((-(i64::MIN as i128)) as u64)
}
negative => Signed::Negative((-negative) as u64),
}
}
}
impl From<isize> for Signed<usize> {
fn from(val: isize) -> Signed<usize> {
skip_assert_initialized!();
match val {
positive if positive.is_positive() => Signed::Positive(positive as usize),
isize::MIN => {
Signed::Negative((-(isize::MIN as i128)) as usize)
}
negative => Signed::Negative((-negative) as usize),
}
}
}
impl From<i32> for Signed<u32> {
fn from(val: i32) -> Signed<u32> {
skip_assert_initialized!();
if val.is_positive() {
Signed::Positive(val as u32)
} else {
Signed::Negative((-(val as i64)) as u32)
}
}
}
pub trait NoneSignedBuilder: FormattedValueNoneBuilder {
type Signed;
fn none_signed() -> Self::Signed;
fn none_signed_for_format(format: Format) -> Self::Signed;
}
impl<T> NoneSignedBuilder for T
where
T: UnsignedIntoSigned + FormattedValueNoneBuilder,
{
type Signed = <T as UnsignedIntoSigned>::Signed;
fn none_signed() -> Self::Signed {
Self::none().into_positive()
}
fn none_signed_for_format(format: Format) -> Self::Signed {
skip_assert_initialized!();
Self::none_for_format(format).into_positive()
}
}