1use 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#[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 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 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}