1use std::{io, sync::Arc};
2
3macro_rules! error {
4 ($fmt:literal $($tt:tt)*) => {
5 ::std::io::Error::new(::std::io::ErrorKind::InvalidInput, format!($fmt $($tt)*))
6 };
7}
8
9pub trait Writer: Sync {
10 fn is_cached(&self, hash: &Hash) -> bool;
11 fn sink(&mut self, hash: &Hash) -> euphony_node::BoxProcessor;
12 fn group<I: Iterator<Item = Entry>>(&mut self, name: &str, hash: &Hash, entries: I);
13 fn buffer<F: FnOnce(Box<dyn BufferReader>) -> Result<Vec<ConvertedBuffer>, E>, E>(
14 &self,
15 path: &str,
16 sample_rate: u64,
17 init: F,
18 ) -> Result<Vec<CachedBuffer>, E>;
19}
20
21pub trait BufferReader: io::Read + Send + Sync + 'static {}
22
23impl<T: io::Read + Send + Sync + 'static> BufferReader for T {}
24
25pub type ConvertedBuffer = Vec<sample::DefaultSample>;
26
27#[derive(Clone, Debug)]
28pub struct CachedBuffer {
29 pub samples: Arc<[f64]>,
30 pub hash: Hash,
31}
32
33#[derive(Clone, Copy, Debug)]
34pub struct Entry {
35 pub sample_offset: u64,
36 pub hash: Hash,
37}
38
39#[path = "sample.rs"]
40mod internal_sample;
41pub mod sample {
42 pub(crate) use super::internal_sample::*;
43 pub use euphony_dsp::sample::*;
44}
45
46pub type Error = std::io::Error;
48pub type Result<T = (), E = Error> = core::result::Result<T, E>;
49pub type Hash = [u8; 32];
50
51mod buffer;
52mod compiler;
53mod group;
54mod instruction;
55mod node;
56mod parallel;
57mod render;
58mod sink;
59
60#[derive(Debug, Default)]
61pub struct Compiler {
62 compiler: compiler::Compiler,
63 render: render::Renderer,
64}
65
66impl Compiler {
67 pub fn compile<I: io::Read, O: Writer>(&mut self, input: &mut I, output: &mut O) -> Result {
68 self.compiler.reset();
70 self.render.reset();
71
72 euphony_command::decode(input, &mut self.compiler)?;
73 let buffers = self.compiler.finalize(output)?;
74 self.render.set_buffers(buffers);
75
76 for instruction in self.compiler.instructions() {
77 self.render
78 .push(instruction, output)
79 .map_err(|err| error!("invalid instruction {:?}", err))?;
80 }
81
82 for (_id, group, entries) in self.compiler.groups() {
83 output.group(&group.name, &group.hash, entries);
84 }
85
86 Ok(())
87 }
88
89 pub fn display<I: io::Read, O: io::Write>(&mut self, input: &mut I, output: &mut O) -> Result {
90 self.compiler.reset();
92 self.render.reset();
93
94 euphony_command::decode(input, &mut self.compiler)?;
95
96 struct Output;
97
98 impl Writer for Output {
99 fn is_cached(&self, _hash: &Hash) -> bool {
100 false
101 }
102
103 fn sink(&mut self, _hash: &Hash) -> euphony_node::BoxProcessor {
104 unimplemented!()
105 }
106
107 fn group<I: Iterator<Item = Entry>>(&mut self, _name: &str, _hash: &Hash, _entries: I) {
108 }
109
110 fn buffer<F: FnOnce(Box<dyn BufferReader>) -> Result<Vec<ConvertedBuffer>, E>, E>(
111 &self,
112 _path: &str,
113 _sample_rate: u64,
114 _init: F,
115 ) -> Result<Vec<CachedBuffer>, E> {
116 unimplemented!()
117 }
118 }
119
120 self.compiler.finalize(&Output)?;
121
122 writeln!(output, "# Groups")?;
123 for (_id, group, entries) in self.compiler.groups() {
124 let count = entries.count();
125 writeln!(output, "* {:?} ({} entries)", group.name, count)?;
126 }
127 writeln!(output)?;
128
129 writeln!(output, "# Instructions")?;
130 for instruction in self.compiler.instructions() {
131 writeln!(output, "{}", instruction)?;
132 }
133
134 Ok(())
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141 use bolero::check;
142 use std::io::Cursor;
143
144 struct Output;
145
146 impl Writer for Output {
147 fn is_cached(&self, _hash: &Hash) -> bool {
148 false
149 }
150
151 fn sink(&mut self, _hash: &Hash) -> euphony_node::BoxProcessor {
152 euphony_dsp::nodes::load(106).unwrap()
154 }
155
156 fn group<I: Iterator<Item = Entry>>(&mut self, _name: &str, _hash: &Hash, entries: I) {
157 for _ in entries {}
158 }
159
160 fn buffer<F: FnOnce(Box<dyn BufferReader>) -> Result<Vec<ConvertedBuffer>, E>, E>(
161 &self,
162 _path: &str,
163 _sample_rate: u64,
164 _init: F,
165 ) -> Result<Vec<CachedBuffer>, E> {
166 Ok(vec![])
167 }
168 }
169
170 #[test]
171 fn fuzz() {
172 check!().for_each(|input| {
173 let mut compiler = Compiler::default();
174 let mut input = Cursor::new(input);
175 let _ = compiler.compile(&mut input, &mut Output);
176 });
177 }
178}