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 ContainsDynamic(ContainsDynamic<N>),
67 Get(Get<N>),
69 GetDynamic(GetDynamic<N>),
71 GetOrUse(GetOrUse<N>),
74 GetOrUseDynamic(GetOrUseDynamic<N>),
77 RandChaCha(RandChaCha<N>),
79 Remove(Remove<N>),
81 Set(Set<N>),
83 BranchEq(BranchEq<N>),
85 BranchNeq(BranchNeq<N>),
87 Position(Position<N>),
89}
90
91impl<N: Network> Command<N> {
92 pub fn is_async(&self) -> bool {
94 matches!(self, Command::Instruction(Instruction::Async(_)))
95 }
96
97 #[inline]
99 pub fn is_await(&self) -> bool {
100 matches!(self, Command::Await(_))
101 }
102
103 pub fn is_call(&self) -> bool {
105 matches!(self, Command::Instruction(Instruction::Call(_) | Instruction::CallDynamic(_)))
106 }
107
108 pub fn is_cast_to_record(&self) -> bool {
110 matches!(self, Command::Instruction(Instruction::Cast(cast)) if matches!(cast.cast_type(), CastType::Record(_) | CastType::ExternalRecord(_)))
111 }
112
113 pub fn is_write(&self) -> bool {
115 matches!(self, Command::Set(_) | Command::Remove(_))
116 }
117
118 pub fn branch_to(&self) -> Option<&Identifier<N>> {
121 match self {
122 Command::BranchEq(branch_eq) => Some(branch_eq.position()),
123 Command::BranchNeq(branch_neq) => Some(branch_neq.position()),
124 _ => None,
125 }
126 }
127
128 pub fn position(&self) -> Option<&Identifier<N>> {
131 match self {
132 Command::Position(position) => Some(position.name()),
133 _ => None,
134 }
135 }
136
137 pub fn destinations(&self) -> Vec<Register<N>> {
139 match self {
140 Command::Instruction(instruction) => instruction.destinations(),
141 Command::Contains(contains) => vec![contains.destination().clone()],
142 Command::ContainsDynamic(contains) => vec![contains.destination().clone()],
143 Command::Get(get) => vec![get.destination().clone()],
144 Command::GetDynamic(get) => vec![get.destination().clone()],
145 Command::GetOrUse(get_or_use) => vec![get_or_use.destination().clone()],
146 Command::GetOrUseDynamic(get_or_use) => vec![get_or_use.destination().clone()],
147 Command::RandChaCha(rand_chacha) => vec![rand_chacha.destination().clone()],
148 Command::Await(_)
149 | Command::BranchEq(_)
150 | Command::BranchNeq(_)
151 | Command::Position(_)
152 | Command::Remove(_)
153 | Command::Set(_) => vec![],
154 }
155 }
156
157 #[inline]
159 pub fn operands(&self) -> &[Operand<N>] {
160 match self {
161 Command::Instruction(c) => c.operands(),
162 Command::Await(c) => c.operands(),
163 Command::Contains(c) => c.operands(),
164 Command::ContainsDynamic(c) => c.operands(),
165 Command::Get(c) => c.operands(),
166 Command::GetDynamic(c) => c.operands(),
167 Command::GetOrUse(c) => c.operands(),
168 Command::GetOrUseDynamic(c) => c.operands(),
169 Command::RandChaCha(c) => c.operands(),
170 Command::Remove(c) => c.operands(),
171 Command::Set(c) => c.operands(),
172 Command::BranchEq(c) => c.operands(),
173 Command::BranchNeq(c) => c.operands(),
174 Command::Position(_) => Default::default(),
175 }
176 }
177
178 pub fn finalize(
180 &self,
181 stack: &impl StackTrait<N>,
182 store: &impl FinalizeStoreTrait<N>,
183 registers: &mut impl FinalizeRegistersState<N>,
184 ) -> Result<Option<FinalizeOperation<N>>> {
185 match self {
186 Command::Instruction(instruction) => {
188 instruction.finalize(stack, registers).map_err(Into::into).map(|_| None)
189 }
190 Command::Await(_) => bail!("`await` commands cannot be finalized directly."),
192 Command::Contains(contains) => contains.finalize(stack, store, registers).map(|_| None),
194 Command::ContainsDynamic(contains_dynamic) => {
196 contains_dynamic.finalize(stack, store, registers).map(|_| None)
197 }
198 Command::Get(get) => get.finalize(stack, store, registers).map(|_| None),
200 Command::GetDynamic(get_dynamic) => get_dynamic.finalize(stack, store, registers).map(|_| None),
202 Command::GetOrUse(get_or_use) => get_or_use.finalize(stack, store, registers).map(|_| None),
204 Command::GetOrUseDynamic(get_or_use_dynamic) => {
206 get_or_use_dynamic.finalize(stack, store, registers).map(|_| None)
207 }
208 Command::RandChaCha(rand_chacha) => rand_chacha.finalize(stack, registers).map(|_| None),
210 Command::Remove(remove) => remove.finalize(stack, store, registers),
212 Command::Set(set) => set.finalize(stack, store, registers).map(Some),
214 Command::BranchEq(_) | Command::BranchNeq(_) => {
216 bail!("`branch` commands cannot be finalized directly.")
217 }
218 Command::Position(position) => position.finalize().map(|_| None),
220 }
221 }
222
223 pub fn contains_external_struct(&self) -> bool {
225 match self {
226 Command::Instruction(c) => c.contains_external_struct(),
227 Command::Await(c) => c.contains_external_struct(),
228 Command::Contains(c) => c.contains_external_struct(),
229 Command::ContainsDynamic(_) => false,
231 Command::Get(c) => c.contains_external_struct(),
232 Command::GetDynamic(c) => c.destination_type().contains_external_struct(),
233 Command::GetOrUse(c) => c.contains_external_struct(),
234 Command::GetOrUseDynamic(c) => c.destination_type().contains_external_struct(),
235 Command::RandChaCha(c) => c.contains_external_struct(),
236 Command::Remove(c) => c.contains_external_struct(),
237 Command::Set(c) => c.contains_external_struct(),
238 Command::BranchEq(c) => c.contains_external_struct(),
239 Command::BranchNeq(c) => c.contains_external_struct(),
240 Command::Position(c) => c.contains_external_struct(),
241 }
242 }
243
244 pub fn contains_string_type(&self) -> bool {
246 self.operands().iter().any(|operand| operand.contains_string_type())
247 }
248
249 pub fn contains_identifier_type(&self) -> Result<bool> {
251 match self {
252 Command::Instruction(instruction) => instruction.contains_identifier_type(),
253 _ => Ok(false),
254 }
255 }
256
257 pub fn exceeds_max_array_size(&self, max_array_size: u32) -> bool {
259 match self {
260 Command::Instruction(instruction) => instruction.exceeds_max_array_size(max_array_size),
261 _ => false,
262 }
263 }
264}
265
266impl<N: Network> FromBytes for Command<N> {
267 fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
269 let variant = u8::read_le(&mut reader)?;
271 match variant {
272 0 => Ok(Self::Instruction(Instruction::read_le(&mut reader)?)),
274 1 => Ok(Self::Await(Await::read_le(&mut reader)?)),
276 2 => Ok(Self::Contains(Contains::read_le(&mut reader)?)),
278 3 => Ok(Self::Get(Get::read_le(&mut reader)?)),
280 4 => Ok(Self::GetOrUse(GetOrUse::read_le(&mut reader)?)),
282 5 => Ok(Self::RandChaCha(RandChaCha::read_le(&mut reader)?)),
284 6 => Ok(Self::Remove(Remove::read_le(&mut reader)?)),
286 7 => Ok(Self::Set(Set::read_le(&mut reader)?)),
288 8 => Ok(Self::BranchEq(BranchEq::read_le(&mut reader)?)),
290 9 => Ok(Self::BranchNeq(BranchNeq::read_le(&mut reader)?)),
292 10 => Ok(Self::Position(Position::read_le(&mut reader)?)),
294 11 => Ok(Self::ContainsDynamic(ContainsDynamic::read_le(&mut reader)?)),
296 12 => Ok(Self::GetDynamic(GetDynamic::read_le(&mut reader)?)),
298 13 => Ok(Self::GetOrUseDynamic(GetOrUseDynamic::read_le(&mut reader)?)),
300 14.. => Err(error(format!("Invalid command variant: {variant}"))),
302 }
303 }
304}
305
306impl<N: Network> ToBytes for Command<N> {
307 fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
309 match self {
310 Self::Instruction(instruction) => {
311 0u8.write_le(&mut writer)?;
313 instruction.write_le(&mut writer)
315 }
316 Self::Await(await_) => {
317 1u8.write_le(&mut writer)?;
319 await_.write_le(&mut writer)
321 }
322 Self::Contains(contains) => {
323 2u8.write_le(&mut writer)?;
325 contains.write_le(&mut writer)
327 }
328 Self::Get(get) => {
329 3u8.write_le(&mut writer)?;
331 get.write_le(&mut writer)
333 }
334 Self::GetOrUse(get_or_use) => {
335 4u8.write_le(&mut writer)?;
337 get_or_use.write_le(&mut writer)
339 }
340 Self::RandChaCha(rand_chacha) => {
341 5u8.write_le(&mut writer)?;
343 rand_chacha.write_le(&mut writer)
345 }
346 Self::Remove(remove) => {
347 6u8.write_le(&mut writer)?;
349 remove.write_le(&mut writer)
351 }
352 Self::Set(set) => {
353 7u8.write_le(&mut writer)?;
355 set.write_le(&mut writer)
357 }
358 Self::BranchEq(branch_eq) => {
359 8u8.write_le(&mut writer)?;
361 branch_eq.write_le(&mut writer)
363 }
364 Self::BranchNeq(branch_neq) => {
365 9u8.write_le(&mut writer)?;
367 branch_neq.write_le(&mut writer)
369 }
370 Self::Position(position) => {
371 10u8.write_le(&mut writer)?;
373 position.write_le(&mut writer)
375 }
376 Self::ContainsDynamic(contains_dynamic) => {
377 11u8.write_le(&mut writer)?;
379 contains_dynamic.write_le(&mut writer)
381 }
382 Self::GetDynamic(get_dynamic) => {
383 12u8.write_le(&mut writer)?;
385 get_dynamic.write_le(&mut writer)
387 }
388 Self::GetOrUseDynamic(get_or_use_dynamic) => {
389 13u8.write_le(&mut writer)?;
391 get_or_use_dynamic.write_le(&mut writer)
393 }
394 }
395 }
396}
397
398impl<N: Network> Parser for Command<N> {
399 #[inline]
401 fn parse(string: &str) -> ParserResult<Self> {
402 alt((
405 map(Await::parse, |await_| Self::Await(await_)),
406 map(ContainsDynamic::parse, |contains_dynamic| Self::ContainsDynamic(contains_dynamic)),
407 map(Contains::parse, |contains| Self::Contains(contains)),
408 map(GetOrUseDynamic::parse, |get_or_use_dynamic| Self::GetOrUseDynamic(get_or_use_dynamic)),
409 map(GetOrUse::parse, |get_or_use| Self::GetOrUse(get_or_use)),
410 map(GetDynamic::parse, |get_dynamic| Self::GetDynamic(get_dynamic)),
411 map(Get::parse, |get| Self::Get(get)),
412 map(RandChaCha::parse, |rand_chacha| Self::RandChaCha(rand_chacha)),
413 map(Remove::parse, |remove| Self::Remove(remove)),
414 map(Set::parse, |set| Self::Set(set)),
415 map(BranchEq::parse, |branch_eq| Self::BranchEq(branch_eq)),
416 map(BranchNeq::parse, |branch_neq| Self::BranchNeq(branch_neq)),
417 map(Position::parse, |position| Self::Position(position)),
418 map(Instruction::parse, |instruction| Self::Instruction(instruction)),
419 ))(string)
420 }
421}
422
423impl<N: Network> FromStr for Command<N> {
424 type Err = Error;
425
426 #[inline]
428 fn from_str(string: &str) -> Result<Self> {
429 match Self::parse(string) {
430 Ok((remainder, object)) => {
431 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
433 Ok(object)
435 }
436 Err(error) => bail!("Failed to parse string. {error}"),
437 }
438 }
439}
440
441impl<N: Network> Debug for Command<N> {
442 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
444 Display::fmt(self, f)
445 }
446}
447
448impl<N: Network> Display for Command<N> {
449 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
451 match self {
452 Self::Instruction(instruction) => Display::fmt(instruction, f),
453 Self::Await(await_) => Display::fmt(await_, f),
454 Self::Contains(contains) => Display::fmt(contains, f),
455 Self::ContainsDynamic(contains_dynamic) => Display::fmt(contains_dynamic, f),
456 Self::Get(get) => Display::fmt(get, f),
457 Self::GetDynamic(get_dynamic) => Display::fmt(get_dynamic, f),
458 Self::GetOrUse(get_or_use) => Display::fmt(get_or_use, f),
459 Self::GetOrUseDynamic(get_or_use_dynamic) => Display::fmt(get_or_use_dynamic, f),
460 Self::RandChaCha(rand_chacha) => Display::fmt(rand_chacha, f),
461 Self::Remove(remove) => Display::fmt(remove, f),
462 Self::Set(set) => Display::fmt(set, f),
463 Self::BranchEq(branch_eq) => Display::fmt(branch_eq, f),
464 Self::BranchNeq(branch_neq) => Display::fmt(branch_neq, f),
465 Self::Position(position) => Display::fmt(position, f),
466 }
467 }
468}
469
470#[cfg(test)]
471mod tests {
472 use super::*;
473 use console::network::MainnetV0;
474
475 type CurrentNetwork = MainnetV0;
476
477 #[test]
478 fn test_command_bytes() {
479 let expected = "decrement object[r0] by r1;";
481 Command::<CurrentNetwork>::parse(expected).unwrap_err();
482
483 let expected = "add r0 r1 into r2;";
485 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
486 let bytes = command.to_bytes_le().unwrap();
487 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
488
489 let expected = "increment object[r0] by r1;";
491 Command::<CurrentNetwork>::parse(expected).unwrap_err();
492
493 let expected = "await r1;";
495 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
496 let bytes = command.to_bytes_le().unwrap();
497 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
498
499 let expected = "contains object[r0] into r1;";
501 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
502 let bytes = command.to_bytes_le().unwrap();
503 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
504
505 let expected = "contains.dynamic r0 r1 r2[r3] into r4;";
507 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
508 let bytes = command.to_bytes_le().unwrap();
509 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
510
511 let expected = "get object[r0] into r1;";
513 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
514 let bytes = command.to_bytes_le().unwrap();
515 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
516
517 let expected = "get.dynamic r0 r1 r2[r3] into r4 as field;";
519 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
520 let bytes = command.to_bytes_le().unwrap();
521 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
522
523 let expected = "get.or_use object[r0] r1 into r2;";
525 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
526 let bytes = command.to_bytes_le().unwrap();
527 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
528
529 let expected = "get.or_use.dynamic r0 r1 r2[r3] r4 into r5 as credits;";
531 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
532 let bytes = command.to_bytes_le().unwrap();
533 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
534
535 let expected = "rand.chacha into r1 as field;";
537 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
538 let bytes = command.to_bytes_le().unwrap();
539 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
540
541 let expected = "rand.chacha r0 r1 into r2 as group;";
543 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
544 let bytes = command.to_bytes_le().unwrap();
545 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
546
547 let expected = "remove object[r0];";
549 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
550 let bytes = command.to_bytes_le().unwrap();
551 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
552
553 let expected = "set r0 into object[r1];";
555 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
556 let bytes = command.to_bytes_le().unwrap();
557 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
558
559 let expected = "branch.eq r0 r1 to exit;";
561 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
562 let bytes = command.to_bytes_le().unwrap();
563 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
564
565 let expected = "branch.neq r2 r3 to start;";
567 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
568 let bytes = command.to_bytes_le().unwrap();
569 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
570
571 let expected = "position exit;";
573 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
574 let bytes = command.to_bytes_le().unwrap();
575 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
576 }
577
578 #[test]
579 fn test_command_parse() {
580 let expected = "decrement object[r0] by r1;";
582 Command::<CurrentNetwork>::parse(expected).unwrap_err();
583
584 let expected = "add r0 r1 into r2;";
586 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
587 assert_eq!(Command::Instruction(Instruction::from_str(expected).unwrap()), command);
588 assert_eq!(expected, command.to_string());
589
590 let expected = "increment object[r0] by r1;";
592 Command::<CurrentNetwork>::parse(expected).unwrap_err();
593
594 let expected = "contains object[r0] into r1;";
596 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
597 assert_eq!(Command::Contains(Contains::from_str(expected).unwrap()), command);
598 assert_eq!(expected, command.to_string());
599
600 let expected = "contains.dynamic r0 r1 r2[r3] into r4;";
602 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
603 assert_eq!(Command::ContainsDynamic(ContainsDynamic::from_str(expected).unwrap()), command);
604 assert_eq!(expected, command.to_string());
605
606 let expected = "get object[r0] into r1;";
608 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
609 assert_eq!(Command::Get(Get::from_str(expected).unwrap()), command);
610 assert_eq!(expected, command.to_string());
611
612 let expected = "get.dynamic r0 r1 r2[r3] into r4 as u8;";
614 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
615 assert_eq!(Command::GetDynamic(GetDynamic::from_str(expected).unwrap()), command);
616 assert_eq!(expected, command.to_string());
617
618 let expected = "get.or_use object[r0] r1 into r2;";
620 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
621 assert_eq!(Command::GetOrUse(GetOrUse::from_str(expected).unwrap()), command);
622 assert_eq!(expected, command.to_string());
623
624 let expected = "get.or_use.dynamic r0 r1 r2[r3] r4 into r5 as Foo;";
626 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
627 assert_eq!(Command::GetOrUseDynamic(GetOrUseDynamic::from_str(expected).unwrap()), command);
628 assert_eq!(expected, command.to_string());
629
630 let expected = "rand.chacha into r1 as field;";
632 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
633 assert_eq!(Command::RandChaCha(RandChaCha::from_str(expected).unwrap()), command);
634 assert_eq!(expected, command.to_string());
635
636 let expected = "rand.chacha r0 r1 into r2 as group;";
638 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
639 assert_eq!(Command::RandChaCha(RandChaCha::from_str(expected).unwrap()), command);
640 assert_eq!(expected, command.to_string());
641
642 let expected = "remove object[r0];";
644 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
645 assert_eq!(Command::Remove(Remove::from_str(expected).unwrap()), command);
646 assert_eq!(expected, command.to_string());
647
648 let expected = "set r0 into object[r1];";
650 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
651 assert_eq!(Command::Set(Set::from_str(expected).unwrap()), command);
652 assert_eq!(expected, command.to_string());
653
654 let expected = "branch.eq r0 r1 to exit;";
656 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
657 assert_eq!(Command::BranchEq(BranchEq::from_str(expected).unwrap()), command);
658 assert_eq!(expected, command.to_string());
659
660 let expected = "branch.neq r2 r3 to start;";
662 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
663 assert_eq!(Command::BranchNeq(BranchNeq::from_str(expected).unwrap()), command);
664 assert_eq!(expected, command.to_string());
665
666 let expected = "position exit;";
668 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
669 assert_eq!(Command::Position(Position::from_str(expected).unwrap()), command);
670 assert_eq!(expected, command.to_string());
671 }
672}