1use crate::error::SampleError;
4use crate::machine::renderer::{Binary, BufId, NodeRenderer, Site, SiteId, Unary};
5
6#[derive(Clone, Copy, Debug, PartialEq)]
7pub(crate) enum Op {
8 Const(f64),
9 Time,
10 Read {
11 id: BufId,
12 shift: i64,
13 },
14 SelfAt {
15 steps: u32,
16 },
17 Add(usize),
18 Mul(usize),
19 Sub,
20 Div,
21 Pow,
22 Map(Unary),
23 Zip(Binary),
24 Crop {
25 a: f64,
26 b: f64,
27 rise: f64,
28 fall: f64,
29 },
30 Join(usize),
31 Channel(usize),
32 Filter(SiteId),
33 Physics(SiteId),
34}
35
36#[derive(Clone, Debug, PartialEq)]
39pub struct Layout {
40 pub width: usize,
41 pub read_widths: Vec<usize>,
42 pub sites: Vec<Site>,
43}
44
45fn meet(a: usize, b: usize) -> Result<usize, SampleError> {
47 match (a, b) {
48 (a, b) if a == b => Ok(a),
49 (1, b) => Ok(b),
50 (a, 1) => Ok(a),
51 (left, right) => Err(SampleError::WidthMismatch { left, right }),
52 }
53}
54
55pub(crate) fn lower(
58 renderer: &NodeRenderer,
59 layout: &Layout,
60 ops: &mut Vec<Op>,
61 widths: &mut Vec<usize>,
62) -> Result<usize, SampleError> {
63 let push = |op: Op, width: usize, ops: &mut Vec<Op>, widths: &mut Vec<usize>| {
64 ops.push(op);
65 widths.push(width);
66 width
67 };
68 let w = match renderer {
69 NodeRenderer::Const(v) => push(Op::Const(*v), 1, ops, widths),
70 NodeRenderer::Time => push(Op::Time, 1, ops, widths),
71 NodeRenderer::Buffer { id, shift } => {
72 let width = layout.read_widths[id.0 as usize];
73 push(
74 Op::Read {
75 id: *id,
76 shift: *shift,
77 },
78 width,
79 ops,
80 widths,
81 )
82 }
83 NodeRenderer::SelfAt { steps } => {
84 push(Op::SelfAt { steps: *steps }, layout.width, ops, widths)
85 }
86 NodeRenderer::Add(parts) | NodeRenderer::Mul(parts) => {
87 let mut width = 1;
88 for p in parts {
89 width = meet(width, lower(p, layout, ops, widths)?)?;
90 }
91 let op = match renderer {
92 NodeRenderer::Add(_) => Op::Add(parts.len()),
93 _ => Op::Mul(parts.len()),
94 };
95 push(op, width, ops, widths)
96 }
97 NodeRenderer::Sub(a, b) | NodeRenderer::Div(a, b) | NodeRenderer::Pow(a, b) => {
98 let wa = lower(a, layout, ops, widths)?;
99 let wb = lower(b, layout, ops, widths)?;
100 let op = match renderer {
101 NodeRenderer::Sub(..) => Op::Sub,
102 NodeRenderer::Div(..) => Op::Div,
103 _ => Op::Pow,
104 };
105 push(op, meet(wa, wb)?, ops, widths)
106 }
107 NodeRenderer::Map(f, x) => {
108 let w = lower(x, layout, ops, widths)?;
109 push(Op::Map(*f), w, ops, widths)
110 }
111 NodeRenderer::Zip(f, a, b) => {
112 let wa = lower(a, layout, ops, widths)?;
113 let wb = lower(b, layout, ops, widths)?;
114 push(Op::Zip(*f), meet(wa, wb)?, ops, widths)
115 }
116 NodeRenderer::Crop {
117 x,
118 a,
119 b,
120 rise,
121 fall,
122 } => {
123 let w = lower(x, layout, ops, widths)?;
124 let crop = Op::Crop {
125 a: *a,
126 b: *b,
127 rise: *rise,
128 fall: *fall,
129 };
130 push(crop, w, ops, widths)
131 }
132 NodeRenderer::Join(parts) => {
133 let mut width = 0;
134 for p in parts {
135 width += lower(p, layout, ops, widths)?;
136 }
137 push(Op::Join(parts.len()), width, ops, widths)
138 }
139 NodeRenderer::Channel { x, k } => {
140 let w = lower(x, layout, ops, widths)?;
141 if *k >= w {
142 return Err(SampleError::ChannelOutOfRange { k: *k, width: w });
143 }
144 push(Op::Channel(*k), 1, ops, widths)
145 }
146 NodeRenderer::Filter {
147 site,
148 x,
149 cutoff,
150 q,
151 gain,
152 } => {
153 let mut width = lower(x, layout, ops, widths)?;
154 for arg in [cutoff, q, gain] {
155 width = meet(width, lower(arg, layout, ops, widths)?)?;
156 }
157 push(Op::Filter(*site), width, ops, widths)
158 }
159 NodeRenderer::Physics { site } => push(Op::Physics(*site), 1, ops, widths),
160 };
161 Ok(w)
162}