use crate::constants::Bitlen;
use crate::data_types::{unsigned, ModeAndLatents, Number, NumberPriv};
use crate::describers::LatentDescriber;
use crate::dyn_latent_slice::DynLatentSlice;
use crate::errors::PcoResult;
use crate::metadata::per_latent_var::PerLatentVar;
use crate::metadata::{ChunkMeta, Mode};
use crate::{describers, ChunkConfig};
use std::ops::*;
pub trait Signed: AddAssign + Copy + Ord + Shr<Bitlen, Output = Self> + Mul<Output = Self> {
const ZERO: Self;
const MAX: Self;
const BITS: Bitlen;
fn from_i64(x: i64) -> Self;
fn to_f64(self) -> f64;
}
macro_rules! impl_signed {
($t: ty, $latent: ty, $header_byte: expr) => {
impl NumberPriv for $t {
const NUMBER_TYPE_BYTE: u8 = $header_byte;
type L = $latent;
fn mode_is_valid(mode: &Mode) -> bool {
unsigned::mode_is_valid::<Self::L>(mode)
}
fn choose_mode_and_split_latents(
nums: &[Self],
config: &ChunkConfig,
) -> PcoResult<ModeAndLatents> {
unsigned::choose_mode_and_split_latents(&nums, config)
}
#[inline]
fn from_latent_ordered(l: Self::L) -> Self {
(l as Self).wrapping_add(Self::MIN)
}
#[inline]
fn to_latent_ordered(self) -> Self::L {
self.wrapping_sub(Self::MIN) as $latent
}
fn join_latents(
mode: &Mode,
primary: DynLatentSlice,
secondary: Option<DynLatentSlice>,
dst: &mut [Self],
) -> PcoResult<()> {
unsigned::join_latents(mode, primary, secondary, dst)
}
}
impl Number for $t {
fn get_latent_describers(meta: &ChunkMeta) -> PerLatentVar<LatentDescriber> {
describers::match_classic_mode::<Self>(meta, "")
.or_else(|| describers::match_int_modes::<Self::L>(meta, true))
.expect("invalid mode for signed type")
}
}
impl Signed for $t {
const BITS: Bitlen = Self::BITS;
const ZERO: Self = 0;
const MAX: Self = Self::MAX;
fn from_i64(x: i64) -> Self {
x as Self
}
fn to_f64(self) -> f64 {
self as f64
}
}
};
}
impl_signed!(i32, u32, 3);
impl_signed!(i64, u64, 4);
impl_signed!(i16, u16, 8);
impl_signed!(i8, u8, 11);
#[cfg(test)]
mod tests {
use crate::data_types::{LatentPriv, NumberPriv};
#[test]
fn test_ordering() {
assert_eq!(i32::MIN.to_latent_ordered(), 0_u32);
assert_eq!((-1_i32).to_latent_ordered(), u32::MID - 1);
assert_eq!(0_i32.to_latent_ordered(), u32::MID);
assert_eq!(i32::MAX.to_latent_ordered(), u32::MAX);
}
}