snarkvm_synthesizer_program/closure/
mod.rs1mod input;
17use input::*;
18
19mod output;
20use output::*;
21
22mod bytes;
23mod parse;
24
25use crate::InstructionTrait;
26use console::{
27 network::prelude::*,
28 program::{Identifier, Register, RegisterType},
29};
30
31use indexmap::IndexSet;
32
33#[derive(Clone, PartialEq, Eq)]
34pub struct ClosureCore<N: Network, Instruction: InstructionTrait<N>> {
35 name: Identifier<N>,
37 inputs: IndexSet<Input<N>>,
40 instructions: Vec<Instruction>,
42 outputs: IndexSet<Output<N>>,
44}
45
46impl<N: Network, Instruction: InstructionTrait<N>> ClosureCore<N, Instruction> {
47 pub fn new(name: Identifier<N>) -> Self {
49 Self { name, inputs: IndexSet::new(), instructions: Vec::new(), outputs: IndexSet::new() }
50 }
51
52 pub const fn name(&self) -> &Identifier<N> {
54 &self.name
55 }
56
57 pub const fn inputs(&self) -> &IndexSet<Input<N>> {
59 &self.inputs
60 }
61
62 pub fn instructions(&self) -> &[Instruction] {
64 &self.instructions
65 }
66
67 pub const fn outputs(&self) -> &IndexSet<Output<N>> {
69 &self.outputs
70 }
71}
72
73impl<N: Network, Instruction: InstructionTrait<N>> ClosureCore<N, Instruction> {
74 #[inline]
81 fn add_input(&mut self, input: Input<N>) -> Result<()> {
82 ensure!(self.instructions.is_empty(), "Cannot add inputs after instructions have been added");
84 ensure!(self.outputs.is_empty(), "Cannot add inputs after outputs have been added");
85
86 ensure!(self.inputs.len() < N::MAX_INPUTS, "Cannot add more than {} inputs", N::MAX_INPUTS);
88 ensure!(!self.inputs.contains(&input), "Cannot add duplicate input statement");
90
91 ensure!(matches!(input.register(), Register::Locator(..)), "Input register must be a locator");
93
94 self.inputs.insert(input);
96 Ok(())
97 }
98
99 #[inline]
105 pub fn add_instruction(&mut self, instruction: Instruction) -> Result<()> {
106 ensure!(self.outputs.is_empty(), "Cannot add instructions after outputs have been added");
108
109 ensure!(
111 self.instructions.len() < N::MAX_INSTRUCTIONS,
112 "Cannot add more than {} instructions",
113 N::MAX_INSTRUCTIONS
114 );
115
116 for register in instruction.destinations() {
118 ensure!(matches!(register, Register::Locator(..)), "Destination register must be a locator");
119 }
120
121 self.instructions.push(instruction);
123 Ok(())
124 }
125
126 #[inline]
131 fn add_output(&mut self, output: Output<N>) -> Result<()> {
132 ensure!(self.outputs.len() < N::MAX_OUTPUTS, "Cannot add more than {} outputs", N::MAX_OUTPUTS);
134
135 ensure!(!matches!(output.register_type(), RegisterType::Record(..)), "Output register cannot be a record");
137
138 self.outputs.insert(output);
140 Ok(())
141 }
142}
143
144impl<N: Network, Instruction: InstructionTrait<N>> TypeName for ClosureCore<N, Instruction> {
145 #[inline]
147 fn type_name() -> &'static str {
148 "closure"
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155
156 use crate::{Closure, Instruction};
157
158 type CurrentNetwork = console::network::MainnetV0;
159
160 #[test]
161 fn test_add_input() {
162 let name = Identifier::from_str("closure_core_test").unwrap();
164 let mut closure = Closure::<CurrentNetwork>::new(name);
165
166 let input = Input::<CurrentNetwork>::from_str("input r0 as field;").unwrap();
168 assert!(closure.add_input(input.clone()).is_ok());
169
170 assert!(closure.add_input(input).is_err());
172
173 for i in 1..CurrentNetwork::MAX_INPUTS * 2 {
175 let input = Input::<CurrentNetwork>::from_str(&format!("input r{i} as field;")).unwrap();
176
177 match closure.inputs.len() < CurrentNetwork::MAX_INPUTS {
178 true => assert!(closure.add_input(input).is_ok()),
179 false => assert!(closure.add_input(input).is_err()),
180 }
181 }
182 }
183
184 #[test]
185 fn test_add_instruction() {
186 let name = Identifier::from_str("closure_core_test").unwrap();
188 let mut closure = Closure::<CurrentNetwork>::new(name);
189
190 let instruction = Instruction::<CurrentNetwork>::from_str("add r0 r1 into r2;").unwrap();
192 assert!(closure.add_instruction(instruction).is_ok());
193
194 for i in 3..CurrentNetwork::MAX_INSTRUCTIONS * 2 {
196 let instruction = Instruction::<CurrentNetwork>::from_str(&format!("add r0 r1 into r{i};")).unwrap();
197
198 match closure.instructions.len() < CurrentNetwork::MAX_INSTRUCTIONS {
199 true => assert!(closure.add_instruction(instruction).is_ok()),
200 false => assert!(closure.add_instruction(instruction).is_err()),
201 }
202 }
203 }
204
205 #[test]
206 fn test_add_output() {
207 let name = Identifier::from_str("closure_core_test").unwrap();
209 let mut closure = Closure::<CurrentNetwork>::new(name);
210
211 let output = Output::<CurrentNetwork>::from_str("output r0 as field;").unwrap();
213 assert!(closure.add_output(output).is_ok());
214
215 for i in 1..CurrentNetwork::MAX_OUTPUTS * 2 {
217 let output = Output::<CurrentNetwork>::from_str(&format!("output r{i} as field;")).unwrap();
218
219 match closure.outputs.len() < CurrentNetwork::MAX_OUTPUTS {
220 true => assert!(closure.add_output(output).is_ok()),
221 false => assert!(closure.add_output(output).is_err()),
222 }
223 }
224 }
225}