Skip to main content

sva_formula/
ty.rs

1// Concern: declares Ty, Held, Codomain, width and the dual property, and the meet | Non-concern: deciding a term's type (infer.rs) | IO: (Ty, Ty) -> Ty
2
3use crate::closed_form::Var;
4
5pub const MAX_WIDTH: u8 = 8;
6
7#[derive(Clone, Copy, Debug, PartialEq, Eq)]
8pub enum Held {
9    Form(Var),
10    Sampled,
11    Frames,
12}
13
14#[derive(Clone, Copy, Debug, PartialEq, Eq)]
15pub enum Codomain {
16    Real,
17    Complex,
18}
19
20/// `dual`: the closed form on the other axis is in A too. Never set on samples or frames.
21#[derive(Clone, Copy, Debug, PartialEq, Eq)]
22pub struct Ty {
23    pub held: Held,
24    pub dual: bool,
25    pub width: u8,
26    pub codomain: Codomain,
27    pub rate: Option<u32>,
28}
29
30#[derive(Clone, Copy, Debug, PartialEq, Eq)]
31pub enum Mismatch {
32    Domain,
33    SamplesInClosedForm,
34    Rate,
35    Frames,
36    Width,
37}
38
39impl Codomain {
40    pub fn join(self, other: Codomain) -> Codomain {
41        match (self, other) {
42            (Codomain::Real, Codomain::Real) => Codomain::Real,
43            _ => Codomain::Complex,
44        }
45    }
46}
47
48impl Held {
49    pub fn is_closed_form(self) -> bool {
50        matches!(self, Held::Form(_))
51    }
52}
53
54impl Ty {
55    pub const fn form(var: Var, dual: bool, codomain: Codomain) -> Ty {
56        Ty {
57            held: Held::Form(var),
58            dual,
59            width: 1,
60            codomain,
61            rate: None,
62        }
63    }
64
65    pub const fn discrete(held: Held, codomain: Codomain) -> Ty {
66        Ty {
67            held,
68            dual: false,
69            width: 1,
70            codomain,
71            rate: None,
72        }
73    }
74
75    pub fn is_closed_form(self) -> bool {
76        self.held.is_closed_form()
77    }
78
79    pub fn has_dual(self) -> bool {
80        self.dual
81    }
82
83    /// One value written two ways, so an expression on `var` reads a dual there.
84    pub fn read_on(self, var: Var) -> Ty {
85        match self.dual && self.is_closed_form() {
86            true => Ty {
87                held: Held::Form(var),
88                ..self
89            },
90            false => self,
91        }
92    }
93
94    /// One axis, a dual only where both have one, the wider width, `Complex` if either is.
95    pub fn meet(self, other: Ty) -> Result<Ty, Mismatch> {
96        let (held, dual) = match (self.held, other.held) {
97            (Held::Form(a), Held::Form(b)) if a == b => (Held::Form(a), self.dual && other.dual),
98            (Held::Form(_), Held::Form(_)) => return Err(Mismatch::Domain),
99            (a, b) if a == b => (a, false),
100            _ => return Err(Mismatch::SamplesInClosedForm),
101        };
102        let width = match (self.width, other.width) {
103            (a, b) if a == b => a,
104            (1, b) => b,
105            (a, 1) => a,
106            _ => return Err(Mismatch::Width),
107        };
108        let rate = match (self.rate, other.rate) {
109            (Some(a), Some(b)) if a != b => return Err(Mismatch::Rate),
110            (a, b) => a.or(b),
111        };
112        Ok(Ty {
113            held,
114            dual,
115            width,
116            codomain: self.codomain.join(other.codomain),
117            rate,
118        })
119    }
120}