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 pub fn contains_external_struct(&self) -> bool {
200 match self {
201 Command::Instruction(c) => c.contains_external_struct(),
202 Command::Await(c) => c.contains_external_struct(),
203 Command::Contains(c) => c.contains_external_struct(),
204 Command::Get(c) => c.contains_external_struct(),
205 Command::GetOrUse(c) => c.contains_external_struct(),
206 Command::RandChaCha(c) => c.contains_external_struct(),
207 Command::Remove(c) => c.contains_external_struct(),
208 Command::Set(c) => c.contains_external_struct(),
209 Command::BranchEq(c) => c.contains_external_struct(),
210 Command::BranchNeq(c) => c.contains_external_struct(),
211 Command::Position(c) => c.contains_external_struct(),
212 }
213 }
214
215 pub fn contains_string_type(&self) -> bool {
217 self.operands().iter().any(|operand| operand.contains_string_type())
218 }
219
220 pub fn exceeds_max_array_size(&self, max_array_size: u32) -> bool {
222 match self {
223 Command::Instruction(instruction) => instruction.exceeds_max_array_size(max_array_size),
224 _ => false,
225 }
226 }
227}
228
229impl<N: Network> FromBytes for Command<N> {
230 fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
232 let variant = u8::read_le(&mut reader)?;
234 match variant {
235 0 => Ok(Self::Instruction(Instruction::read_le(&mut reader)?)),
237 1 => Ok(Self::Await(Await::read_le(&mut reader)?)),
239 2 => Ok(Self::Contains(Contains::read_le(&mut reader)?)),
241 3 => Ok(Self::Get(Get::read_le(&mut reader)?)),
243 4 => Ok(Self::GetOrUse(GetOrUse::read_le(&mut reader)?)),
245 5 => Ok(Self::RandChaCha(RandChaCha::read_le(&mut reader)?)),
247 6 => Ok(Self::Remove(Remove::read_le(&mut reader)?)),
249 7 => Ok(Self::Set(Set::read_le(&mut reader)?)),
251 8 => Ok(Self::BranchEq(BranchEq::read_le(&mut reader)?)),
253 9 => Ok(Self::BranchNeq(BranchNeq::read_le(&mut reader)?)),
255 10 => Ok(Self::Position(Position::read_le(&mut reader)?)),
257 11.. => Err(error(format!("Invalid command variant: {variant}"))),
259 }
260 }
261}
262
263impl<N: Network> ToBytes for Command<N> {
264 fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
266 match self {
267 Self::Instruction(instruction) => {
268 0u8.write_le(&mut writer)?;
270 instruction.write_le(&mut writer)
272 }
273 Self::Await(await_) => {
274 1u8.write_le(&mut writer)?;
276 await_.write_le(&mut writer)
278 }
279 Self::Contains(contains) => {
280 2u8.write_le(&mut writer)?;
282 contains.write_le(&mut writer)
284 }
285 Self::Get(get) => {
286 3u8.write_le(&mut writer)?;
288 get.write_le(&mut writer)
290 }
291 Self::GetOrUse(get_or_use) => {
292 4u8.write_le(&mut writer)?;
294 get_or_use.write_le(&mut writer)
296 }
297 Self::RandChaCha(rand_chacha) => {
298 5u8.write_le(&mut writer)?;
300 rand_chacha.write_le(&mut writer)
302 }
303 Self::Remove(remove) => {
304 6u8.write_le(&mut writer)?;
306 remove.write_le(&mut writer)
308 }
309 Self::Set(set) => {
310 7u8.write_le(&mut writer)?;
312 set.write_le(&mut writer)
314 }
315 Self::BranchEq(branch_eq) => {
316 8u8.write_le(&mut writer)?;
318 branch_eq.write_le(&mut writer)
320 }
321 Self::BranchNeq(branch_neq) => {
322 9u8.write_le(&mut writer)?;
324 branch_neq.write_le(&mut writer)
326 }
327 Self::Position(position) => {
328 10u8.write_le(&mut writer)?;
330 position.write_le(&mut writer)
332 }
333 }
334 }
335}
336
337impl<N: Network> Parser for Command<N> {
338 #[inline]
340 fn parse(string: &str) -> ParserResult<Self> {
341 alt((
344 map(Await::parse, |await_| Self::Await(await_)),
345 map(Contains::parse, |contains| Self::Contains(contains)),
346 map(GetOrUse::parse, |get_or_use| Self::GetOrUse(get_or_use)),
347 map(Get::parse, |get| Self::Get(get)),
348 map(RandChaCha::parse, |rand_chacha| Self::RandChaCha(rand_chacha)),
349 map(Remove::parse, |remove| Self::Remove(remove)),
350 map(Set::parse, |set| Self::Set(set)),
351 map(BranchEq::parse, |branch_eq| Self::BranchEq(branch_eq)),
352 map(BranchNeq::parse, |branch_neq| Self::BranchNeq(branch_neq)),
353 map(Position::parse, |position| Self::Position(position)),
354 map(Instruction::parse, |instruction| Self::Instruction(instruction)),
355 ))(string)
356 }
357}
358
359impl<N: Network> FromStr for Command<N> {
360 type Err = Error;
361
362 #[inline]
364 fn from_str(string: &str) -> Result<Self> {
365 match Self::parse(string) {
366 Ok((remainder, object)) => {
367 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
369 Ok(object)
371 }
372 Err(error) => bail!("Failed to parse string. {error}"),
373 }
374 }
375}
376
377impl<N: Network> Debug for Command<N> {
378 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
380 Display::fmt(self, f)
381 }
382}
383
384impl<N: Network> Display for Command<N> {
385 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
387 match self {
388 Self::Instruction(instruction) => Display::fmt(instruction, f),
389 Self::Await(await_) => Display::fmt(await_, f),
390 Self::Contains(contains) => Display::fmt(contains, f),
391 Self::Get(get) => Display::fmt(get, f),
392 Self::GetOrUse(get_or_use) => Display::fmt(get_or_use, f),
393 Self::RandChaCha(rand_chacha) => Display::fmt(rand_chacha, f),
394 Self::Remove(remove) => Display::fmt(remove, f),
395 Self::Set(set) => Display::fmt(set, f),
396 Self::BranchEq(branch_eq) => Display::fmt(branch_eq, f),
397 Self::BranchNeq(branch_neq) => Display::fmt(branch_neq, f),
398 Self::Position(position) => Display::fmt(position, f),
399 }
400 }
401}
402
403#[cfg(test)]
404mod tests {
405 use super::*;
406 use console::network::MainnetV0;
407
408 type CurrentNetwork = MainnetV0;
409
410 #[test]
411 fn test_command_bytes() {
412 let expected = "decrement object[r0] by r1;";
414 Command::<CurrentNetwork>::parse(expected).unwrap_err();
415
416 let expected = "add r0 r1 into r2;";
418 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
419 let bytes = command.to_bytes_le().unwrap();
420 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
421
422 let expected = "increment object[r0] by r1;";
424 Command::<CurrentNetwork>::parse(expected).unwrap_err();
425
426 let expected = "await r1;";
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 = "contains object[r0] into r1;";
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 = "get object[r0] into 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 = "get.or_use object[r0] r1 into r2;";
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 = "rand.chacha into r1 as field;";
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 = "rand.chacha r0 r1 into r2 as group;";
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 let expected = "remove object[r0];";
464 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
465 let bytes = command.to_bytes_le().unwrap();
466 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
467
468 let expected = "set r0 into object[r1];";
470 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
471 let bytes = command.to_bytes_le().unwrap();
472 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
473
474 let expected = "branch.eq r0 r1 to exit;";
476 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
477 let bytes = command.to_bytes_le().unwrap();
478 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
479
480 let expected = "branch.neq r2 r3 to start;";
482 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
483 let bytes = command.to_bytes_le().unwrap();
484 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
485
486 let expected = "position exit;";
488 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
489 let bytes = command.to_bytes_le().unwrap();
490 assert_eq!(command, Command::from_bytes_le(&bytes).unwrap());
491 }
492
493 #[test]
494 fn test_command_parse() {
495 let expected = "decrement object[r0] by r1;";
497 Command::<CurrentNetwork>::parse(expected).unwrap_err();
498
499 let expected = "add r0 r1 into r2;";
501 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
502 assert_eq!(Command::Instruction(Instruction::from_str(expected).unwrap()), command);
503 assert_eq!(expected, command.to_string());
504
505 let expected = "increment object[r0] by r1;";
507 Command::<CurrentNetwork>::parse(expected).unwrap_err();
508
509 let expected = "contains object[r0] into r1;";
511 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
512 assert_eq!(Command::Contains(Contains::from_str(expected).unwrap()), command);
513 assert_eq!(expected, command.to_string());
514
515 let expected = "get object[r0] into r1;";
517 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
518 assert_eq!(Command::Get(Get::from_str(expected).unwrap()), command);
519 assert_eq!(expected, command.to_string());
520
521 let expected = "get.or_use object[r0] r1 into r2;";
523 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
524 assert_eq!(Command::GetOrUse(GetOrUse::from_str(expected).unwrap()), command);
525 assert_eq!(expected, command.to_string());
526
527 let expected = "rand.chacha into r1 as field;";
529 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
530 assert_eq!(Command::RandChaCha(RandChaCha::from_str(expected).unwrap()), command);
531 assert_eq!(expected, command.to_string());
532
533 let expected = "rand.chacha r0 r1 into r2 as group;";
535 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
536 assert_eq!(Command::RandChaCha(RandChaCha::from_str(expected).unwrap()), command);
537 assert_eq!(expected, command.to_string());
538
539 let expected = "remove object[r0];";
541 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
542 assert_eq!(Command::Remove(Remove::from_str(expected).unwrap()), command);
543 assert_eq!(expected, command.to_string());
544
545 let expected = "set r0 into object[r1];";
547 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
548 assert_eq!(Command::Set(Set::from_str(expected).unwrap()), command);
549 assert_eq!(expected, command.to_string());
550
551 let expected = "branch.eq r0 r1 to exit;";
553 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
554 assert_eq!(Command::BranchEq(BranchEq::from_str(expected).unwrap()), command);
555 assert_eq!(expected, command.to_string());
556
557 let expected = "branch.neq r2 r3 to start;";
559 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
560 assert_eq!(Command::BranchNeq(BranchNeq::from_str(expected).unwrap()), command);
561 assert_eq!(expected, command.to_string());
562
563 let expected = "position exit;";
565 let command = Command::<CurrentNetwork>::parse(expected).unwrap().1;
566 assert_eq!(Command::Position(Position::from_str(expected).unwrap()), command);
567 assert_eq!(expected, command.to_string());
568 }
569}