Skip to main content

number_general/
class.rs

1use std::cmp::Ordering;
2use std::fmt;
3use std::iter::{Product, Sum};
4use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
5
6use safecast::{CastFrom, CastInto};
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10use super::instance::{Boolean, Complex, Float, Int, UInt};
11use super::{Number, _Complex};
12
13/// Defines common properties of numeric types supported by [`Number`].
14pub trait NumberClass: Default + Into<NumberType> + Ord + Send + fmt::Display {
15    type Instance: NumberInstance;
16
17    /// Cast the given `Number` into an instance of this type.
18    fn cast(&self, n: Number) -> Self::Instance;
19
20    /// Return `true` if this is a complex type.
21    fn is_complex(&self) -> bool {
22        false
23    }
24
25    /// Return `false` if this is a complex type.
26    fn is_real(&self) -> bool {
27        !self.is_complex()
28    }
29
30    /// Return the maximum size of this type of [`Number`], in bits.
31    fn size(self) -> usize;
32
33    /// Return `1` as an instance of this type.
34    fn one(&self) -> <Self as NumberClass>::Instance;
35
36    /// Return `0` as an instance of this type.
37    fn zero(&self) -> <Self as NumberClass>::Instance;
38}
39
40/// Defines common operations on numeric types supported by [`Number`].
41pub trait NumberInstance:
42    Copy
43    + Default
44    + Sized
45    + From<Boolean>
46    + Into<Number>
47    + Add<Output = Self>
48    + AddAssign
49    + Sub<Output = Self>
50    + SubAssign
51    + Mul<Output = Self>
52    + MulAssign
53    + Div<Output = Self>
54    + DivAssign
55    + Product
56    + Sum
57    + fmt::Debug
58    + fmt::Display
59{
60    type Abs: NumberInstance;
61    type Exp: NumberInstance;
62    type Log: NumberInstance;
63    type Round: NumberInstance;
64    type Class: NumberClass<Instance = Self>;
65
66    /// Get an impl of [`NumberClass`] describing this number.
67    fn class(&self) -> Self::Class;
68
69    /// Cast this number into the specified [`NumberClass`].
70    fn into_type(
71        self,
72        dtype: <Self as NumberInstance>::Class,
73    ) -> <<Self as NumberInstance>::Class as NumberClass>::Instance;
74
75    /// Calculate the absolute value of this number.
76    fn abs(self) -> Self::Abs;
77
78    /// Raise `e` to the power of this number.
79    fn exp(self) -> Self::Exp;
80
81    /// Compute the natural logarithm of this number.
82    fn ln(self) -> Self::Log;
83
84    /// Compute the logarithm of this number with respect to the given `base`.
85    fn log<N: NumberInstance>(self, base: N) -> Self::Log
86    where
87        Float: From<N>;
88
89    /// Raise this number to the given exponent.
90    ///
91    /// Panics: if the given exponent is a complex number.
92    fn pow(self, exp: Number) -> Self;
93
94    /// Return `true` if `self` and `other` are nonzero.
95    fn and(self, other: Self) -> Self
96    where
97        Boolean: CastFrom<Self>,
98    {
99        Boolean::cast_from(self)
100            .and(Boolean::cast_from(other))
101            .into()
102    }
103
104    /// Return `true` if this number is zero.
105    fn not(self) -> Self
106    where
107        Boolean: CastFrom<Self>,
108    {
109        Boolean::cast_from(self).not().into()
110    }
111
112    /// Return `true` if `self` or `other` is nonzero.
113    fn or(self, other: Self) -> Self
114    where
115        Boolean: CastFrom<Self>,
116    {
117        let this = Boolean::cast_from(self);
118        let that = Boolean::cast_from(other);
119        this.or(that).into()
120    }
121
122    /// Return this number rounded to the nearest integer.
123    fn round(self) -> Self::Round;
124
125    /// Return `true` if exactly one of `self` and `other` is zero.
126    fn xor(self, other: Self) -> Self
127    where
128        Boolean: CastFrom<Self>,
129    {
130        let this = Boolean::cast_from(self);
131        let that = Boolean::cast_from(other);
132        this.xor(that).into()
133    }
134}
135
136/// Trigonometric functions.
137pub trait Trigonometry {
138    type Out: NumberInstance;
139
140    /// Arcsine
141    fn asin(self) -> Self::Out;
142
143    /// Sine
144    fn sin(self) -> Self::Out;
145
146    /// Hyperbolic arcsine
147    fn asinh(self) -> Self::Out;
148
149    /// Hyperbolic sine
150    fn sinh(self) -> Self::Out;
151
152    /// Hyperbolic arccosine
153    fn acos(self) -> Self::Out;
154
155    /// Cosine
156    fn cos(self) -> Self::Out;
157
158    /// Hyperbolic arccosine
159    fn acosh(self) -> Self::Out;
160
161    /// Hyperbolic cosine
162    fn cosh(self) -> Self::Out;
163
164    /// Arctangent
165    fn atan(self) -> Self::Out;
166
167    /// Tangent
168    fn tan(self) -> Self::Out;
169
170    /// Hyperbolic arctangent
171    fn atanh(self) -> Self::Out;
172
173    /// Hyperbolic tangent
174    fn tanh(self) -> Self::Out;
175}
176
177/// Defines common operations on real (i.e. not `Complex`) numbers.
178pub trait RealInstance: PartialEq + PartialOrd + Sized {
179    const ONE: Self;
180    const ZERO: Self;
181
182    /// Return `true` if this is zero or a positive number.
183    fn is_positive(&self) -> bool {
184        self >= &Self::ZERO
185    }
186
187    /// Return `true` if this is a negative number.
188    fn is_negative(&self) -> bool {
189        self < &Self::ZERO
190    }
191
192    /// Return `true` if this is zero.
193    fn is_zero(&self) -> bool {
194        self == &Self::ZERO
195    }
196}
197
198/// Defines common operations on floating-point numeric types.
199pub trait FloatInstance {
200    /// Return `true` if this `Number` is infinite (e.g. [`f32::INFINITY`]).
201    fn is_infinite(&self) -> bool;
202
203    /// Return `true` if this is not a valid number (NaN).
204    fn is_nan(&self) -> bool;
205}
206
207/// The type of a [`Complex`] number.
208#[derive(Clone, Copy, Default, Hash, Eq, PartialEq)]
209#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
210pub enum ComplexType {
211    C32,
212    C64,
213    #[default]
214    Complex,
215}
216
217impl NumberClass for ComplexType {
218    type Instance = Complex;
219
220    fn cast(&self, n: Number) -> Complex {
221        match self {
222            Self::C64 => Complex::C64(n.cast_into()),
223            _ => Complex::C32(n.cast_into()),
224        }
225    }
226
227    fn is_complex(&self) -> bool {
228        true
229    }
230
231    fn size(self) -> usize {
232        match self {
233            Self::C32 => 8,
234            Self::C64 => 16,
235            Self::Complex => 16,
236        }
237    }
238
239    fn one(&self) -> Complex {
240        match self {
241            Self::C32 => _Complex::<f32>::new(1f32, 0f32).into(),
242            Self::C64 => _Complex::<f64>::new(1f64, 0f64).into(),
243            Self::Complex => _Complex::<f32>::new(1f32, 0f32).into(),
244        }
245    }
246
247    fn zero(&self) -> Complex {
248        match self {
249            Self::C32 => _Complex::<f32>::new(0f32, 0f32).into(),
250            Self::C64 => _Complex::<f64>::new(0f64, 0f64).into(),
251            Self::Complex => _Complex::<f32>::new(0f32, 0f32).into(),
252        }
253    }
254}
255
256impl Ord for ComplexType {
257    fn cmp(&self, other: &Self) -> Ordering {
258        match (self, other) {
259            (Self::C32, Self::C32) => Ordering::Equal,
260            (Self::C64, Self::C64) => Ordering::Equal,
261            (Self::Complex, Self::Complex) => Ordering::Equal,
262
263            (Self::Complex, _) => Ordering::Greater,
264            (_, Self::Complex) => Ordering::Less,
265
266            (Self::C64, Self::C32) => Ordering::Greater,
267            (Self::C32, Self::C64) => Ordering::Less,
268        }
269    }
270}
271
272impl PartialOrd for ComplexType {
273    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
274        Some(self.cmp(other))
275    }
276}
277
278impl From<ComplexType> for NumberType {
279    fn from(ct: ComplexType) -> NumberType {
280        Self::Complex(ct)
281    }
282}
283
284impl fmt::Debug for ComplexType {
285    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
286        fmt::Display::fmt(self, f)
287    }
288}
289
290impl fmt::Display for ComplexType {
291    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
292        match self {
293            Self::C32 => write!(f, "32-bit complex number"),
294            Self::C64 => write!(f, "64-bit complex number"),
295            Self::Complex => write!(f, "complex number"),
296        }
297    }
298}
299
300/// The type of a [`Boolean`].
301#[derive(Clone, Copy, Default, Hash, Eq, PartialEq)]
302#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
303pub struct BooleanType;
304
305impl NumberClass for BooleanType {
306    type Instance = Boolean;
307
308    fn cast(&self, n: Number) -> Boolean {
309        n.cast_into()
310    }
311
312    fn size(self) -> usize {
313        1
314    }
315
316    fn one(&self) -> Boolean {
317        true.into()
318    }
319
320    fn zero(&self) -> Boolean {
321        false.into()
322    }
323}
324
325impl Ord for BooleanType {
326    fn cmp(&self, _other: &Self) -> Ordering {
327        Ordering::Equal
328    }
329}
330
331impl PartialOrd for BooleanType {
332    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
333        Some(self.cmp(other))
334    }
335}
336
337impl From<BooleanType> for NumberType {
338    fn from(_bt: BooleanType) -> NumberType {
339        NumberType::Bool
340    }
341}
342
343impl fmt::Debug for BooleanType {
344    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
345        fmt::Display::fmt(self, f)
346    }
347}
348
349impl fmt::Display for BooleanType {
350    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
351        write!(f, "Boolean")
352    }
353}
354
355/// The type of a [`Float`].
356#[derive(Clone, Copy, Default, Hash, Eq, PartialEq)]
357#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
358pub enum FloatType {
359    F32,
360    F64,
361    #[default]
362    Float,
363}
364
365impl NumberClass for FloatType {
366    type Instance = Float;
367
368    fn cast(&self, n: Number) -> Float {
369        match self {
370            Self::F64 => Float::F64(n.cast_into()),
371            _ => Float::F32(n.cast_into()),
372        }
373    }
374
375    fn size(self) -> usize {
376        match self {
377            Self::F32 => 4,
378            Self::F64 => 8,
379            Self::Float => 8,
380        }
381    }
382
383    fn one(&self) -> Float {
384        match self {
385            Self::F32 => 1f32.into(),
386            Self::F64 => 1f64.into(),
387            Self::Float => 1f32.into(),
388        }
389    }
390
391    fn zero(&self) -> Float {
392        match self {
393            Self::F32 => 0f32.into(),
394            Self::F64 => 0f64.into(),
395            Self::Float => 0f32.into(),
396        }
397    }
398}
399
400impl Ord for FloatType {
401    fn cmp(&self, other: &Self) -> Ordering {
402        match (self, other) {
403            (Self::F32, Self::F32) => Ordering::Equal,
404            (Self::F64, Self::F64) => Ordering::Equal,
405            (Self::Float, Self::Float) => Ordering::Equal,
406
407            (Self::Float, _) => Ordering::Greater,
408            (_, Self::Float) => Ordering::Less,
409
410            (Self::F64, Self::F32) => Ordering::Greater,
411            (Self::F32, Self::F64) => Ordering::Less,
412        }
413    }
414}
415
416impl PartialOrd for FloatType {
417    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
418        Some(self.cmp(other))
419    }
420}
421
422impl From<FloatType> for NumberType {
423    fn from(ft: FloatType) -> NumberType {
424        NumberType::Float(ft)
425    }
426}
427
428impl fmt::Debug for FloatType {
429    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
430        fmt::Display::fmt(self, f)
431    }
432}
433
434impl fmt::Display for FloatType {
435    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
436        use FloatType::*;
437        match self {
438            F32 => write!(f, "32-bit float"),
439            F64 => write!(f, "64-bit float"),
440            Float => write!(f, "float"),
441        }
442    }
443}
444
445/// The type of an [`Int`].
446#[derive(Clone, Copy, Default, Hash, Eq, PartialEq)]
447#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
448pub enum IntType {
449    I8,
450    I16,
451    I32,
452    I64,
453    #[default]
454    Int,
455}
456
457impl NumberClass for IntType {
458    type Instance = Int;
459
460    fn cast(&self, n: Number) -> Int {
461        match self {
462            Self::I8 => Int::I8(n.cast_into()),
463            Self::I16 => Int::I16(n.cast_into()),
464            Self::Int | Self::I32 => Int::I32(n.cast_into()),
465            Self::I64 => Int::I64(n.cast_into()),
466        }
467    }
468
469    fn size(self) -> usize {
470        match self {
471            Self::I8 => 1,
472            Self::I16 => 2,
473            Self::I32 => 4,
474            Self::I64 => 8,
475            Self::Int => 8,
476        }
477    }
478
479    fn one(&self) -> Int {
480        match self {
481            Self::I8 => 1i8.into(),
482            Self::I16 => 1i16.into(),
483            Self::I32 => 1i32.into(),
484            Self::I64 => 1i64.into(),
485            Self::Int => 1i16.into(),
486        }
487    }
488
489    fn zero(&self) -> Int {
490        match self {
491            Self::I8 => 0i8.into(),
492            Self::I16 => 0i16.into(),
493            Self::I32 => 0i32.into(),
494            Self::I64 => 0i64.into(),
495            Self::Int => 0i16.into(),
496        }
497    }
498}
499
500impl Ord for IntType {
501    fn cmp(&self, other: &Self) -> Ordering {
502        match (self, other) {
503            (this, that) if this == that => Ordering::Equal,
504
505            (Self::Int, _) => Ordering::Greater,
506            (_, Self::Int) => Ordering::Less,
507
508            (Self::I64, _) => Ordering::Greater,
509            (_, Self::I64) => Ordering::Less,
510
511            (Self::I32, _) => Ordering::Greater,
512            (_, Self::I32) => Ordering::Less,
513
514            (Self::I16, _) => Ordering::Greater,
515            (_, Self::I16) => Ordering::Less,
516
517            (Self::I8, _) => Ordering::Less,
518        }
519    }
520}
521
522impl PartialOrd for IntType {
523    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
524        Some(self.cmp(other))
525    }
526}
527
528impl From<IntType> for NumberType {
529    fn from(it: IntType) -> NumberType {
530        NumberType::Int(it)
531    }
532}
533
534impl fmt::Debug for IntType {
535    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
536        fmt::Display::fmt(self, f)
537    }
538}
539
540impl fmt::Display for IntType {
541    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
542        match self {
543            Self::I8 => write!(f, "8-bit integer"),
544            Self::I16 => write!(f, "16-bit integer"),
545            Self::I32 => write!(f, "32-bit integer"),
546            Self::I64 => write!(f, "64-bit integer"),
547            Self::Int => write!(f, "integer"),
548        }
549    }
550}
551
552/// The type of a [`UInt`].
553#[derive(Clone, Copy, Default, Hash, Eq, PartialEq)]
554#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
555pub enum UIntType {
556    U8,
557    U16,
558    U32,
559    U64,
560    #[default]
561    UInt,
562}
563
564impl NumberClass for UIntType {
565    type Instance = UInt;
566
567    fn cast(&self, n: Number) -> UInt {
568        match self {
569            Self::U8 => UInt::U8(n.cast_into()),
570            Self::U16 => UInt::U16(n.cast_into()),
571            Self::UInt | Self::U32 => UInt::U32(n.cast_into()),
572            Self::U64 => UInt::U64(n.cast_into()),
573        }
574    }
575
576    fn size(self) -> usize {
577        match self {
578            UIntType::U8 => 1,
579            UIntType::U16 => 2,
580            UIntType::U32 => 4,
581            UIntType::U64 => 8,
582            UIntType::UInt => 8,
583        }
584    }
585
586    fn one(&self) -> UInt {
587        match self {
588            Self::U8 => 1u8.into(),
589            Self::U16 => 1u16.into(),
590            Self::U32 => 1u32.into(),
591            Self::U64 => 1u64.into(),
592            Self::UInt => 1u8.into(),
593        }
594    }
595
596    fn zero(&self) -> UInt {
597        match self {
598            Self::U8 => 0u8.into(),
599            Self::U16 => 0u16.into(),
600            Self::U32 => 0u32.into(),
601            Self::U64 => 0u64.into(),
602            Self::UInt => 0u8.into(),
603        }
604    }
605}
606
607impl Ord for UIntType {
608    fn cmp(&self, other: &Self) -> Ordering {
609        match (self, other) {
610            (Self::U8, Self::U8) => Ordering::Equal,
611            (Self::U16, Self::U16) => Ordering::Equal,
612            (Self::U32, Self::U32) => Ordering::Equal,
613            (Self::U64, Self::U64) => Ordering::Equal,
614            (Self::UInt, Self::UInt) => Ordering::Equal,
615
616            (Self::UInt, _) => Ordering::Greater,
617            (_, Self::UInt) => Ordering::Less,
618
619            (Self::U64, _) => Ordering::Greater,
620            (_, Self::U64) => Ordering::Less,
621
622            (Self::U8, _) => Ordering::Less,
623            (_, Self::U8) => Ordering::Greater,
624
625            (Self::U32, Self::U16) => Ordering::Greater,
626            (Self::U16, Self::U32) => Ordering::Less,
627        }
628    }
629}
630
631impl PartialOrd for UIntType {
632    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
633        Some(self.cmp(other))
634    }
635}
636
637impl From<UIntType> for NumberType {
638    fn from(ut: UIntType) -> NumberType {
639        NumberType::UInt(ut)
640    }
641}
642
643impl fmt::Debug for UIntType {
644    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
645        fmt::Display::fmt(self, f)
646    }
647}
648
649impl fmt::Display for UIntType {
650    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
651        use UIntType::*;
652        match self {
653            U8 => write!(f, "8-bit unsigned"),
654            U16 => write!(f, "16-bit unsigned"),
655            U32 => write!(f, "32-bit unsigned"),
656            U64 => write!(f, "64-bit unsigned"),
657            UInt => write!(f, "uint"),
658        }
659    }
660}
661
662/// The type of a generic [`Number`].
663#[derive(Clone, Copy, Default, Hash, Eq, PartialEq)]
664#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
665pub enum NumberType {
666    Bool,
667    Complex(ComplexType),
668    Float(FloatType),
669    Int(IntType),
670    UInt(UIntType),
671    #[default]
672    Number,
673}
674
675impl NumberType {
676    pub fn uint64() -> Self {
677        NumberType::UInt(UIntType::U64)
678    }
679}
680
681impl NumberClass for NumberType {
682    type Instance = Number;
683
684    fn is_complex(&self) -> bool {
685        match self {
686            Self::Bool => BooleanType.is_complex(),
687            Self::Complex(ct) => ct.is_complex(),
688            Self::Float(ft) => ft.is_complex(),
689            Self::Int(it) => it.is_complex(),
690            Self::UInt(ut) => ut.is_complex(),
691            Self::Number => false,
692        }
693    }
694
695    fn cast(&self, n: Number) -> Number {
696        match self {
697            Self::Bool => Number::Bool(n.cast_into()),
698            Self::Complex(ct) => Number::Complex(ct.cast(n)),
699            Self::Float(ft) => Number::Float(ft.cast(n)),
700            Self::Int(it) => Number::Int(it.cast(n)),
701            Self::UInt(ut) => Number::UInt(ut.cast(n)),
702            Self::Number => n,
703        }
704    }
705
706    fn size(self) -> usize {
707        use NumberType::*;
708        match self {
709            Bool => 1,
710            Complex(ct) => NumberClass::size(ct),
711            Float(ft) => NumberClass::size(ft),
712            Int(it) => NumberClass::size(it),
713            UInt(ut) => NumberClass::size(ut),
714
715            // a generic Number still has a distinct maximum size
716            Number => NumberClass::size(ComplexType::C64),
717        }
718    }
719
720    fn one(&self) -> Number {
721        use NumberType::*;
722        match self {
723            Bool | Number => true.into(),
724            Complex(ct) => ct.one().into(),
725            Float(ft) => ft.one().into(),
726            Int(it) => it.one().into(),
727            UInt(ut) => ut.one().into(),
728        }
729    }
730
731    fn zero(&self) -> Number {
732        use NumberType::*;
733        match self {
734            Bool | Number => false.into(),
735            Complex(ct) => ct.zero().into(),
736            Float(ft) => ft.zero().into(),
737            Int(it) => it.zero().into(),
738            UInt(ut) => ut.zero().into(),
739        }
740    }
741}
742
743impl Ord for NumberType {
744    fn cmp(&self, other: &Self) -> Ordering {
745        match (self, other) {
746            (Self::Bool, Self::Bool) => Ordering::Equal,
747            (Self::Complex(l), Self::Complex(r)) => l.cmp(r),
748            (Self::Float(l), Self::Float(r)) => l.cmp(r),
749            (Self::Int(l), Self::Int(r)) => l.cmp(r),
750            (Self::UInt(l), Self::UInt(r)) => l.cmp(r),
751
752            (Self::Number, Self::Number) => Ordering::Equal,
753            (Self::Number, _) => Ordering::Greater,
754            (_, Self::Number) => Ordering::Less,
755
756            (Self::Bool, _) => Ordering::Less,
757            (_, Self::Bool) => Ordering::Greater,
758
759            (Self::Complex(_), _) => Ordering::Greater,
760            (_, Self::Complex(_)) => Ordering::Less,
761
762            (Self::UInt(_), Self::Int(_)) => Ordering::Less,
763            (Self::UInt(_), Self::Float(_)) => Ordering::Less,
764            (Self::Int(_), Self::UInt(_)) => Ordering::Greater,
765            (Self::Float(_), Self::UInt(_)) => Ordering::Greater,
766            (Self::Int(_), Self::Float(_)) => Ordering::Less,
767            (Self::Float(_), Self::Int(_)) => Ordering::Greater,
768        }
769    }
770}
771
772impl PartialOrd for NumberType {
773    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
774        Some(self.cmp(other))
775    }
776}
777
778impl fmt::Debug for NumberType {
779    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
780        fmt::Display::fmt(self, f)
781    }
782}
783
784impl fmt::Display for NumberType {
785    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
786        use NumberType::*;
787        match self {
788            Bool => fmt::Debug::fmt(&BooleanType, f),
789            Complex(ct) => fmt::Debug::fmt(ct, f),
790            Float(ft) => fmt::Debug::fmt(ft, f),
791            Int(it) => fmt::Debug::fmt(it, f),
792            UInt(ut) => fmt::Debug::fmt(ut, f),
793            Number => write!(f, "Number"),
794        }
795    }
796}