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 FinalizeStoreTrait,
48 Instruction,
49 Operand,
50 StackTrait,
51};
52use console::{
53 network::{error, prelude::*},
54 program::{Identifier, Register},
55};
56
57#[derive(Clone, PartialEq, Eq, Hash)]
58pub enum Command<N: Network> {
59 Instruction(Instruction<N>),
61 Await(Await<N>),
63 Contains(Contains<N>),
65 Get(Get<N>),
67 GetOrUse(GetOrUse<N>),
70 RandChaCha(RandChaCha<N>),
72 Remove(Remove<N>),
74 Set(Set<N>),
76 BranchEq(BranchEq<N>),
78 BranchNeq(BranchNeq<N>),
80 Position(Position<N>),
82}
83
84impl<N: Network> Command<N> {
85 pub fn is_async(&self) -> bool {
87 matches!(self, Command::Instruction(Instruction::Async(_)))
88 }
89
90 #[inline]
92 pub fn is_await(&self) -> bool {
93 matches!(self, Command::Await(_))
94 }
95
96 pub fn is_call(&self) -> bool {
98 matches!(self, Command::Instruction(Instruction::Call(_)))
99 }
100
101 pub fn is_cast_to_record(&self) -> bool {
103 matches!(self, Command::Instruction(Instruction::Cast(cast)) if matches!(cast.cast_type(), CastType::Record(_) | CastType::ExternalRecord(_)))
104 }
105
106 pub fn is_write(&self) -> bool {
108 matches!(self, Command::Set(_) | Command::Remove(_))
109 }
110
111 pub fn branch_to(&self) -> Option<&Identifier<N>> {
114 match self {
115 Command::BranchEq(branch_eq) => Some(branch_eq.position()),
116 Command::BranchNeq(branch_neq) => Some(branch_neq.position()),
117 _ => None,
118 }
119 }
120
121 pub fn position(&self) -> Option<&Identifier<N>> {
124 match self {
125 Command::Position(position) => Some(position.name()),
126 _ => None,
127 }
128 }
129
130 pub fn destinations(&self) -> Vec<Register<N>> {
132 match self {
133 Command::Instruction(instruction) => instruction.destinations(),
134 Command::Contains(contains) => vec![contains.destination().clone()],
135 Command::Get(get) => vec![get.destination().clone()],
136 Command::GetOrUse(get_or_use) => vec![get_or_use.destination().clone()],
137 Command::RandChaCha(rand_chacha) => vec![rand_chacha.destination().clone()],
138 Command::Await(_)
139 | Command::BranchEq(_)
140 | Command::BranchNeq(_)
141 | Command::Position(_)
142 | Command::Remove(_)
143 | Command::Set(_) => vec![],
144 }
145 }
146
147 #[inline]
149 pub fn operands(&self) -> &[Operand<N>] {
150 match self {
151 Command::Instruction(c) => c.operands(),
152 Command::Await(c) => c.operands(),
153 Command::Contains(c) => c.operands(),
154 Command::Get(c) => c.operands(),
155 Command::GetOrUse(c) => c.operands(),
156 Command::RandChaCha(c) => c.operands(),
157 Command::Remove(c) => c.operands(),
158 Command::Set(c) => c.operands(),
159 Command::BranchEq(c) => c.operands(),
160 Command::BranchNeq(c) => c.operands(),
161 Command::Position(_) => Default::default(),
162 }
163 }
164
165 pub fn finalize(
167 &self,
168 stack: &impl StackTrait<N>,
169 store: &impl FinalizeStoreTrait<N>,
170 registers: &mut impl FinalizeRegistersState<N>,
171 ) -> Result<Option<FinalizeOperation<N>>> {
172 match self {
173 Command::Instruction(instruction) => instruction.finalize(stack, registers).map(|_| None),
175 Command::Await(_) => bail!("`await` commands cannot be finalized directly."),
177 Command::Contains(contains) => contains.finalize(stack, store, registers).map(|_| None),
179 Command::Get(get) => get.finalize(stack, store, registers).map(|_| None),
181 Command::GetOrUse(get_or_use) => get_or_use.finalize(stack, store, registers).map(|_| None),
183 Command::RandChaCha(rand_chacha) => rand_chacha.finalize(stack, registers).map(|_| None),
185 Command::Remove(remove) => remove.finalize(stack, store, registers),
187 Command::Set(set) => set.finalize(stack, store, registers).map(Some),
189 Command::BranchEq(_) | Command::BranchNeq(_) => {
191 bail!("`branch` commands cannot be finalized directly.")
192 }
193 Command::Position(position) => position.finalize().map(|_| None),
195 }
196 }
197}
198
199impl<N: Network> FromBytes for Command<N> {
200 fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
202 let variant = u8::read_le(&mut reader)?;
204 match variant {
205 0 => Ok(Self::Instruction(Instruction::read_le(&mut reader)?)),
207 1 => Ok(Self::Await(Await::read_le(&mut reader)?)),
209 2 => Ok(Self::Contains(Contains::read_le(&mut reader)?)),
211 3 => Ok(Self::Get(Get::read_le(&mut reader)?)),
213 4 => Ok(Self::GetOrUse(GetOrUse::read_le(&mut reader)?)),
215 5 => Ok(Self::RandChaCha(RandChaCha::read_le(&mut reader)?)),
217 6 => Ok(Self::Remove(Remove::read_le(&mut reader)?)),
219 7 => Ok(Self::Set(Set::read_le(&mut reader)?)),
221 8 => Ok(Self::BranchEq(BranchEq::read_le(&mut reader)?)),
223 9 => Ok(Self::BranchNeq(BranchNeq::read_le(&mut reader)?)),
225 10 => Ok(Self::Position(Position::read_le(&mut reader)?)),
227 11.. => Err(error(format!("Invalid command variant: {variant}"))),
229 }
230 }
231}
232
233impl<N: Network> ToBytes for Command<N> {
234 fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
236 match self {
237 Self::Instruction(instruction) => {
238 0u8.write_le(&mut writer)?;
240 instruction.write_le(&mut writer)
242 }
243 Self::Await(await_) => {
244 1u8.write_le(&mut writer)?;
246 await_.write_le(&mut writer)
248 }
249 Self::Contains(contains) => {
250 2u8.write_le(&mut writer)?;
252 contains.write_le(&mut writer)
254 }
255 Self::Get(get) => {
256 3u8.write_le(&mut writer)?;
258 get.write_le(&mut writer)
260 }
261 Self::GetOrUse(get_or_use) => {
262 4u8.write_le(&mut writer)?;
264 get_or_use.write_le(&mut writer)
266 }
267 Self::RandChaCha(rand_chacha) => {
268 5u8.write_le(&mut writer)?;
270 rand_chacha.write_le(&mut writer)
272 }
273 Self::Remove(remove) => {
274 6u8.write_le(&mut writer)?;
276 remove.write_le(&mut writer)
278 }
279 Self::Set(set) => {
280 7u8.write_le(&mut writer)?;
282 set.write_le(&mut writer)
284 }
285 Self::BranchEq(branch_eq) => {
286 8u8.write_le(&mut writer)?;
288 branch_eq.write_le(&mut writer)
290 }
291 Self::BranchNeq(branch_neq) => {
292 9u8.write_le(&mut writer)?;
294 branch_neq.write_le(&mut writer)
296 }
297 Self::Position(position) => {
298 10u8.write_le(&mut writer)?;
300 position.write_le(&mut writer)
302 }
303 }
304 }
305}
306
307impl<N: Network> Parser for Command<N> {
308 #[inline]
310 fn parse(string: &str) -> ParserResult<Self> {
311 alt((
314 map(Await::parse, |await_| Self::Await(await_)),
315 map(Contains::parse, |contains| Self::Contains(contains)),
316 map(GetOrUse::parse, |get_or_use| Self::GetOrUse(get_or_use)),
317 map(Get::parse, |get| Self::Get(get)),
318 map(RandChaCha::parse, |rand_chacha| Self::RandChaCha(rand_chacha)),
319 map(Remove::parse, |remove| Self::Remove(remove)),
320 map(Set::parse, |set| Self::Set(set)),
321 map(BranchEq::parse, |branch_eq| Self::BranchEq(branch_eq)),
322 map(BranchNeq::parse, |branch_neq| Self::BranchNeq(branch_neq)),
323 map(Position::parse, |position| Self::Position(position)),
324 map(Instruction::parse, |instruction| Self::Instruction(instruction)),
325 ))(string)
326 }
327}
328
329impl<N: Network> FromStr for Command<N> {
330 type Err = Error;
331
332 #[inline]
334 fn from_str(string: &str) -> Result<Self> {
335 match Self::parse(string) {
336 Ok((remainder, object)) => {
337 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
339 Ok(object)
341 }
342 Err(error) => bail!("Failed to parse string. {error}"),
343 }
344 }
345}
346
347impl<N: Network> Debug for Command<N> {
348 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
350 Display::fmt(self, f)
351 }
352}
353
354impl<N: Network> Display for Command<N> {
355 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
357 match self {
358 Self::Instruction(instruction) => Display::fmt(instruction, f),
359 Self::Await(await_) => Display::fmt(await_, f),
360 Self::Contains(contains) => Display::fmt(contains, f),
361 Self::Get(get) => Display::fmt(get, f),
362 Self::GetOrUse(get_or_use) => Display::fmt(get_or_use, f),
363 Self::RandChaCha(rand_chacha) => Display::fmt(rand_chacha, f),
364 Self::Remove(remove) => Display::fmt(remove, f),
365 Self::Set(set) => Display::fmt(set, f),
366 Self::BranchEq(branch_eq) => Display::fmt(branch_eq, f),
367 Self::BranchNeq(branch_neq) => Display::fmt(branch_neq, f),
368 Self::Position(position) => Display::fmt(position, f),
369 }
370 }
371}
372
373#[cfg(test)]
374mod tests {
375 use super::*;
376 use console::network::MainnetV0;
377
378 type CurrentNetwork = MainnetV0;
379
380 #[test]
381 fn test_command_bytes() {
382 let expected = "decrement object[r0] by r1;";
384 Command::<CurrentNetwork>::parse(expected).unwrap_err();
385
386 let expected = "add r0 r1 into r2;";
388 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
389 let bytes = command.to_bytes_le().unwrap();
390 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
391
392 let expected = "increment object[r0] by r1;";
394 Command::<CurrentNetwork>::parse(expected).unwrap_err();
395
396 let expected = "await r1;";
398 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
399 let bytes = command.to_bytes_le().unwrap();
400 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
401
402 let expected = "contains object[r0] into r1;";
404 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
405 let bytes = command.to_bytes_le().unwrap();
406 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
407
408 let expected = "get object[r0] into r1;";
410 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
411 let bytes = command.to_bytes_le().unwrap();
412 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
413
414 let expected = "get.or_use object[r0] r1 into r2;";
416 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
417 let bytes = command.to_bytes_le().unwrap();
418 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
419
420 let expected = "rand.chacha into r1 as field;";
422 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
423 let bytes = command.to_bytes_le().unwrap();
424 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
425
426 let expected = "rand.chacha r0 r1 into r2 as group;";
428 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
429 let bytes = command.to_bytes_le().unwrap();
430 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
431
432 let expected = "remove object[r0];";
434 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
435 let bytes = command.to_bytes_le().unwrap();
436 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
437
438 let expected = "set r0 into object[r1];";
440 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
441 let bytes = command.to_bytes_le().unwrap();
442 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
443
444 let expected = "branch.eq r0 r1 to exit;";
446 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
447 let bytes = command.to_bytes_le().unwrap();
448 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
449
450 let expected = "branch.neq r2 r3 to start;";
452 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
453 let bytes = command.to_bytes_le().unwrap();
454 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
455
456 let expected = "position exit;";
458 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
459 let bytes = command.to_bytes_le().unwrap();
460 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
461 }
462
463 #[test]
464 fn test_command_parse() {
465 let expected = "decrement object[r0] by r1;";
467 Command::<CurrentNetwork>::parse(expected).unwrap_err();
468
469 let expected = "add r0 r1 into r2;";
471 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
472 assert_eq!(Command::Instruction(Instruction::from_str(expected).unwrap()), command);
473 assert_eq!(expected, command.to_string());
474
475 let expected = "increment object[r0] by r1;";
477 Command::<CurrentNetwork>::parse(expected).unwrap_err();
478
479 let expected = "contains object[r0] into r1;";
481 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
482 assert_eq!(Command::Contains(Contains::from_str(expected).unwrap()), command);
483 assert_eq!(expected, command.to_string());
484
485 let expected = "get object[r0] into r1;";
487 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
488 assert_eq!(Command::Get(Get::from_str(expected).unwrap()), command);
489 assert_eq!(expected, command.to_string());
490
491 let expected = "get.or_use object[r0] r1 into r2;";
493 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
494 assert_eq!(Command::GetOrUse(GetOrUse::from_str(expected).unwrap()), command);
495 assert_eq!(expected, command.to_string());
496
497 let expected = "rand.chacha into r1 as field;";
499 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
500 assert_eq!(Command::RandChaCha(RandChaCha::from_str(expected).unwrap()), command);
501 assert_eq!(expected, command.to_string());
502
503 let expected = "rand.chacha r0 r1 into r2 as group;";
505 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
506 assert_eq!(Command::RandChaCha(RandChaCha::from_str(expected).unwrap()), command);
507 assert_eq!(expected, command.to_string());
508
509 let expected = "remove object[r0];";
511 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
512 assert_eq!(Command::Remove(Remove::from_str(expected).unwrap()), command);
513 assert_eq!(expected, command.to_string());
514
515 let expected = "set r0 into object[r1];";
517 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
518 assert_eq!(Command::Set(Set::from_str(expected).unwrap()), command);
519 assert_eq!(expected, command.to_string());
520
521 let expected = "branch.eq r0 r1 to exit;";
523 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
524 assert_eq!(Command::BranchEq(BranchEq::from_str(expected).unwrap()), command);
525 assert_eq!(expected, command.to_string());
526
527 let expected = "branch.neq r2 r3 to start;";
529 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
530 assert_eq!(Command::BranchNeq(BranchNeq::from_str(expected).unwrap()), command);
531 assert_eq!(expected, command.to_string());
532
533 let expected = "position exit;";
535 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
536 assert_eq!(Command::Position(Position::from_str(expected).unwrap()), command);
537 assert_eq!(expected, command.to_string());
538 }
539}