Skip to main content

prism/
primitives.rs

1use serde::de::{self, Visitor};
2use serde::{Deserialize, Deserializer, Serialize, Serializer};
3use std::fmt;
4pub use std::num::NonZeroUsize;
5
6/// A smoothing or probability factor in [0.0, 1.0].
7#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
8pub struct UnitFraction(f64);
9
10impl UnitFraction {
11    pub fn new(v: f64) -> Result<Self, String> {
12        if (0.0..=1.0).contains(&v) {
13            Ok(Self(v))
14        } else {
15            Err(format!("{v} is outside [0.0, 1.0]"))
16        }
17    }
18    pub fn value(self) -> f64 {
19        self.0
20    }
21}
22
23impl Serialize for UnitFraction {
24    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
25        s.serialize_f64(self.0)
26    }
27}
28
29struct UnitFractionVisitor;
30
31impl Visitor<'_> for UnitFractionVisitor {
32    type Value = UnitFraction;
33
34    fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
35        f.write_str("a float in [0.0, 1.0]")
36    }
37
38    fn visit_f64<E: de::Error>(self, v: f64) -> Result<UnitFraction, E> {
39        UnitFraction::new(v).map_err(de::Error::custom)
40    }
41
42    fn visit_i64<E: de::Error>(self, v: i64) -> Result<UnitFraction, E> {
43        self.visit_f64(v as f64)
44    }
45
46    fn visit_u64<E: de::Error>(self, v: u64) -> Result<UnitFraction, E> {
47        self.visit_f64(v as f64)
48    }
49}
50
51impl<'de> Deserialize<'de> for UnitFraction {
52    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
53        d.deserialize_f64(UnitFractionVisitor)
54    }
55}
56
57/// A positive z-score threshold (> 0.0).
58#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
59pub struct ZScoreThreshold(f64);
60
61impl ZScoreThreshold {
62    pub fn new(v: f64) -> Result<Self, String> {
63        if v > 0.0 {
64            Ok(Self(v))
65        } else {
66            Err(format!("{v} must be > 0.0"))
67        }
68    }
69    pub fn value(self) -> f64 {
70        self.0
71    }
72}
73
74impl Serialize for ZScoreThreshold {
75    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
76        s.serialize_f64(self.0)
77    }
78}
79
80struct ZScoreThresholdVisitor;
81
82impl Visitor<'_> for ZScoreThresholdVisitor {
83    type Value = ZScoreThreshold;
84
85    fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
86        f.write_str("a float > 0.0")
87    }
88
89    fn visit_f64<E: de::Error>(self, v: f64) -> Result<ZScoreThreshold, E> {
90        ZScoreThreshold::new(v).map_err(de::Error::custom)
91    }
92
93    fn visit_i64<E: de::Error>(self, v: i64) -> Result<ZScoreThreshold, E> {
94        self.visit_f64(v as f64)
95    }
96
97    fn visit_u64<E: de::Error>(self, v: u64) -> Result<ZScoreThreshold, E> {
98        self.visit_f64(v as f64)
99    }
100}
101
102impl<'de> Deserialize<'de> for ZScoreThreshold {
103    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
104        d.deserialize_f64(ZScoreThresholdVisitor)
105    }
106}