1mod await_;
17pub use await_::*;
18
19mod branch;
20pub use branch::*;
21
22mod contains;
23pub use contains::*;
24
25mod get;
26pub use get::*;
27
28mod get_or_use;
29pub use get_or_use::*;
30
31mod rand_chacha;
32pub use crate::command::rand_chacha::*;
33
34mod remove;
35pub use remove::*;
36
37mod position;
38pub use position::*;
39
40mod set;
41pub use set::*;
42
43use crate::{
44 CastType,
45 FinalizeOperation,
46 FinalizeRegistersState,
47 Instruction,
48 traits::{
49 CommandTrait,
50 FinalizeStoreTrait,
51 InstructionTrait,
52 RegistersLoad,
53 RegistersStore,
54 StackMatches,
55 StackProgram,
56 },
57};
58use console::{
59 network::prelude::*,
60 program::{Identifier, Register},
61};
62
63#[derive(Clone, PartialEq, Eq, Hash)]
64pub enum Command<N: Network> {
65 Instruction(Instruction<N>),
67 Await(Await<N>),
69 Contains(Contains<N>),
71 Get(Get<N>),
73 GetOrUse(GetOrUse<N>),
76 RandChaCha(RandChaCha<N>),
78 Remove(Remove<N>),
80 Set(Set<N>),
82 BranchEq(BranchEq<N>),
84 BranchNeq(BranchNeq<N>),
86 Position(Position<N>),
88}
89
90impl<N: Network> CommandTrait<N> for Command<N> {
91 #[inline]
93 fn destinations(&self) -> Vec<Register<N>> {
94 match self {
95 Command::Instruction(instruction) => instruction.destinations(),
96 Command::Contains(contains) => vec![contains.destination().clone()],
97 Command::Get(get) => vec![get.destination().clone()],
98 Command::GetOrUse(get_or_use) => vec![get_or_use.destination().clone()],
99 Command::RandChaCha(rand_chacha) => vec![rand_chacha.destination().clone()],
100 Command::Await(_)
101 | Command::BranchEq(_)
102 | Command::BranchNeq(_)
103 | Command::Position(_)
104 | Command::Remove(_)
105 | Command::Set(_) => vec![],
106 }
107 }
108
109 #[inline]
112 fn branch_to(&self) -> Option<&Identifier<N>> {
113 match self {
114 Command::BranchEq(branch_eq) => Some(branch_eq.position()),
115 Command::BranchNeq(branch_neq) => Some(branch_neq.position()),
116 _ => None,
117 }
118 }
119
120 #[inline]
123 fn position(&self) -> Option<&Identifier<N>> {
124 match self {
125 Command::Position(position) => Some(position.name()),
126 _ => None,
127 }
128 }
129
130 #[inline]
132 fn is_call(&self) -> bool {
133 matches!(self, Command::Instruction(Instruction::Call(_)))
134 }
135
136 fn is_cast_to_record(&self) -> bool {
138 matches!(self, Command::Instruction(Instruction::Cast(cast)) if matches!(cast.cast_type(), CastType::Record(_) | CastType::ExternalRecord(_)))
139 }
140
141 #[inline]
143 fn is_write(&self) -> bool {
144 matches!(self, Command::Set(_) | Command::Remove(_))
145 }
146}
147
148impl<N: Network> Command<N> {
149 #[inline]
151 pub fn finalize(
152 &self,
153 stack: &(impl StackMatches<N> + StackProgram<N>),
154 store: &impl FinalizeStoreTrait<N>,
155 registers: &mut (impl RegistersLoad<N> + RegistersStore<N> + FinalizeRegistersState<N>),
156 ) -> Result<Option<FinalizeOperation<N>>> {
157 match self {
158 Command::Instruction(instruction) => instruction.finalize(stack, registers).map(|_| None),
160 Command::Await(_) => bail!("`await` commands cannot be finalized directly."),
162 Command::Contains(contains) => contains.finalize(stack, store, registers).map(|_| None),
164 Command::Get(get) => get.finalize(stack, store, registers).map(|_| None),
166 Command::GetOrUse(get_or_use) => get_or_use.finalize(stack, store, registers).map(|_| None),
168 Command::RandChaCha(rand_chacha) => rand_chacha.finalize(stack, registers).map(|_| None),
170 Command::Remove(remove) => remove.finalize(stack, store, registers),
172 Command::Set(set) => set.finalize(stack, store, registers).map(Some),
174 Command::BranchEq(_) | Command::BranchNeq(_) => {
176 bail!("`branch` commands cannot be finalized directly.")
177 }
178 Command::Position(position) => position.finalize().map(|_| None),
180 }
181 }
182}
183
184impl<N: Network> FromBytes for Command<N> {
185 fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
187 let variant = u8::read_le(&mut reader)?;
189 match variant {
190 0 => Ok(Self::Instruction(Instruction::read_le(&mut reader)?)),
192 1 => Ok(Self::Await(Await::read_le(&mut reader)?)),
194 2 => Ok(Self::Contains(Contains::read_le(&mut reader)?)),
196 3 => Ok(Self::Get(Get::read_le(&mut reader)?)),
198 4 => Ok(Self::GetOrUse(GetOrUse::read_le(&mut reader)?)),
200 5 => Ok(Self::RandChaCha(RandChaCha::read_le(&mut reader)?)),
202 6 => Ok(Self::Remove(Remove::read_le(&mut reader)?)),
204 7 => Ok(Self::Set(Set::read_le(&mut reader)?)),
206 8 => Ok(Self::BranchEq(BranchEq::read_le(&mut reader)?)),
208 9 => Ok(Self::BranchNeq(BranchNeq::read_le(&mut reader)?)),
210 10 => Ok(Self::Position(Position::read_le(&mut reader)?)),
212 11.. => Err(error(format!("Invalid command variant: {variant}"))),
214 }
215 }
216}
217
218impl<N: Network> ToBytes for Command<N> {
219 fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
221 match self {
222 Self::Instruction(instruction) => {
223 0u8.write_le(&mut writer)?;
225 instruction.write_le(&mut writer)
227 }
228 Self::Await(await_) => {
229 1u8.write_le(&mut writer)?;
231 await_.write_le(&mut writer)
233 }
234 Self::Contains(contains) => {
235 2u8.write_le(&mut writer)?;
237 contains.write_le(&mut writer)
239 }
240 Self::Get(get) => {
241 3u8.write_le(&mut writer)?;
243 get.write_le(&mut writer)
245 }
246 Self::GetOrUse(get_or_use) => {
247 4u8.write_le(&mut writer)?;
249 get_or_use.write_le(&mut writer)
251 }
252 Self::RandChaCha(rand_chacha) => {
253 5u8.write_le(&mut writer)?;
255 rand_chacha.write_le(&mut writer)
257 }
258 Self::Remove(remove) => {
259 6u8.write_le(&mut writer)?;
261 remove.write_le(&mut writer)
263 }
264 Self::Set(set) => {
265 7u8.write_le(&mut writer)?;
267 set.write_le(&mut writer)
269 }
270 Self::BranchEq(branch_eq) => {
271 8u8.write_le(&mut writer)?;
273 branch_eq.write_le(&mut writer)
275 }
276 Self::BranchNeq(branch_neq) => {
277 9u8.write_le(&mut writer)?;
279 branch_neq.write_le(&mut writer)
281 }
282 Self::Position(position) => {
283 10u8.write_le(&mut writer)?;
285 position.write_le(&mut writer)
287 }
288 }
289 }
290}
291
292impl<N: Network> Parser for Command<N> {
293 #[inline]
295 fn parse(string: &str) -> ParserResult<Self> {
296 alt((
299 map(Await::parse, |await_| Self::Await(await_)),
300 map(Contains::parse, |contains| Self::Contains(contains)),
301 map(GetOrUse::parse, |get_or_use| Self::GetOrUse(get_or_use)),
302 map(Get::parse, |get| Self::Get(get)),
303 map(RandChaCha::parse, |rand_chacha| Self::RandChaCha(rand_chacha)),
304 map(Remove::parse, |remove| Self::Remove(remove)),
305 map(Set::parse, |set| Self::Set(set)),
306 map(BranchEq::parse, |branch_eq| Self::BranchEq(branch_eq)),
307 map(BranchNeq::parse, |branch_neq| Self::BranchNeq(branch_neq)),
308 map(Position::parse, |position| Self::Position(position)),
309 map(Instruction::parse, |instruction| Self::Instruction(instruction)),
310 ))(string)
311 }
312}
313
314impl<N: Network> FromStr for Command<N> {
315 type Err = Error;
316
317 #[inline]
319 fn from_str(string: &str) -> Result<Self> {
320 match Self::parse(string) {
321 Ok((remainder, object)) => {
322 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
324 Ok(object)
326 }
327 Err(error) => bail!("Failed to parse string. {error}"),
328 }
329 }
330}
331
332impl<N: Network> Debug for Command<N> {
333 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
335 Display::fmt(self, f)
336 }
337}
338
339impl<N: Network> Display for Command<N> {
340 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
342 match self {
343 Self::Instruction(instruction) => Display::fmt(instruction, f),
344 Self::Await(await_) => Display::fmt(await_, f),
345 Self::Contains(contains) => Display::fmt(contains, f),
346 Self::Get(get) => Display::fmt(get, f),
347 Self::GetOrUse(get_or_use) => Display::fmt(get_or_use, f),
348 Self::RandChaCha(rand_chacha) => Display::fmt(rand_chacha, f),
349 Self::Remove(remove) => Display::fmt(remove, f),
350 Self::Set(set) => Display::fmt(set, f),
351 Self::BranchEq(branch_eq) => Display::fmt(branch_eq, f),
352 Self::BranchNeq(branch_neq) => Display::fmt(branch_neq, f),
353 Self::Position(position) => Display::fmt(position, f),
354 }
355 }
356}
357
358#[cfg(test)]
359mod tests {
360 use super::*;
361 use console::network::MainnetV0;
362
363 type CurrentNetwork = MainnetV0;
364
365 #[test]
366 fn test_command_bytes() {
367 let expected = "decrement object[r0] by r1;";
369 Command::<CurrentNetwork>::parse(expected).unwrap_err();
370
371 let expected = "add r0 r1 into r2;";
373 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
374 let bytes = command.to_bytes_le().unwrap();
375 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
376
377 let expected = "increment object[r0] by r1;";
379 Command::<CurrentNetwork>::parse(expected).unwrap_err();
380
381 let expected = "await r1;";
383 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
384 let bytes = command.to_bytes_le().unwrap();
385 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
386
387 let expected = "contains object[r0] into r1;";
389 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
390 let bytes = command.to_bytes_le().unwrap();
391 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
392
393 let expected = "get object[r0] into r1;";
395 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
396 let bytes = command.to_bytes_le().unwrap();
397 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
398
399 let expected = "get.or_use object[r0] r1 into r2;";
401 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
402 let bytes = command.to_bytes_le().unwrap();
403 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
404
405 let expected = "rand.chacha into r1 as field;";
407 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
408 let bytes = command.to_bytes_le().unwrap();
409 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
410
411 let expected = "rand.chacha r0 r1 into r2 as group;";
413 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
414 let bytes = command.to_bytes_le().unwrap();
415 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
416
417 let expected = "remove object[r0];";
419 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
420 let bytes = command.to_bytes_le().unwrap();
421 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
422
423 let expected = "set r0 into object[r1];";
425 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
426 let bytes = command.to_bytes_le().unwrap();
427 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
428
429 let expected = "branch.eq r0 r1 to exit;";
431 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
432 let bytes = command.to_bytes_le().unwrap();
433 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
434
435 let expected = "branch.neq r2 r3 to start;";
437 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
438 let bytes = command.to_bytes_le().unwrap();
439 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
440
441 let expected = "position exit;";
443 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
444 let bytes = command.to_bytes_le().unwrap();
445 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
446 }
447
448 #[test]
449 fn test_command_parse() {
450 let expected = "decrement object[r0] by r1;";
452 Command::<CurrentNetwork>::parse(expected).unwrap_err();
453
454 let expected = "add r0 r1 into r2;";
456 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
457 assert_eq!(Command::Instruction(Instruction::from_str(expected).unwrap()), command);
458 assert_eq!(expected, command.to_string());
459
460 let expected = "increment object[r0] by r1;";
462 Command::<CurrentNetwork>::parse(expected).unwrap_err();
463
464 let expected = "contains object[r0] into r1;";
466 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
467 assert_eq!(Command::Contains(Contains::from_str(expected).unwrap()), command);
468 assert_eq!(expected, command.to_string());
469
470 let expected = "get object[r0] into r1;";
472 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
473 assert_eq!(Command::Get(Get::from_str(expected).unwrap()), command);
474 assert_eq!(expected, command.to_string());
475
476 let expected = "get.or_use object[r0] r1 into r2;";
478 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
479 assert_eq!(Command::GetOrUse(GetOrUse::from_str(expected).unwrap()), command);
480 assert_eq!(expected, command.to_string());
481
482 let expected = "rand.chacha into r1 as field;";
484 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
485 assert_eq!(Command::RandChaCha(RandChaCha::from_str(expected).unwrap()), command);
486 assert_eq!(expected, command.to_string());
487
488 let expected = "rand.chacha r0 r1 into r2 as group;";
490 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
491 assert_eq!(Command::RandChaCha(RandChaCha::from_str(expected).unwrap()), command);
492 assert_eq!(expected, command.to_string());
493
494 let expected = "remove object[r0];";
496 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
497 assert_eq!(Command::Remove(Remove::from_str(expected).unwrap()), command);
498 assert_eq!(expected, command.to_string());
499
500 let expected = "set r0 into object[r1];";
502 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
503 assert_eq!(Command::Set(Set::from_str(expected).unwrap()), command);
504 assert_eq!(expected, command.to_string());
505
506 let expected = "branch.eq r0 r1 to exit;";
508 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
509 assert_eq!(Command::BranchEq(BranchEq::from_str(expected).unwrap()), command);
510 assert_eq!(expected, command.to_string());
511
512 let expected = "branch.neq r2 r3 to start;";
514 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
515 assert_eq!(Command::BranchNeq(BranchNeq::from_str(expected).unwrap()), command);
516 assert_eq!(expected, command.to_string());
517
518 let expected = "position exit;";
520 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
521 assert_eq!(Command::Position(Position::from_str(expected).unwrap()), command);
522 assert_eq!(expected, command.to_string());
523 }
524}