use crate::{Opcode, Operand, Registers, Stack};
use console::{network::prelude::*, program::Register};
pub type FinalizeCommand<N> = FinalizeOperation<N, { Variant::FinalizeCommand as u8 }>;
enum Variant {
FinalizeCommand,
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct FinalizeOperation<N: Network, const VARIANT: u8> {
operands: Vec<Operand<N>>,
}
impl<N: Network, const VARIANT: u8> FinalizeOperation<N, VARIANT> {
#[inline]
pub const fn opcode() -> Opcode {
match VARIANT {
0 => Opcode::Finalize("finalize"),
_ => panic!("Invalid 'finalize' instruction opcode"),
}
}
#[inline]
pub fn operands(&self) -> &[Operand<N>] {
debug_assert!(self.operands.len() <= N::MAX_INPUTS, "Finalize must have less than {} operands", N::MAX_INPUTS);
&self.operands
}
#[inline]
pub fn destinations(&self) -> Vec<Register<N>> {
vec![]
}
}
impl<N: Network, const VARIANT: u8> FinalizeOperation<N, VARIANT> {
#[inline]
pub fn evaluate<A: circuit::Aleo<Network = N>>(
&self,
stack: &Stack<N>,
registers: &mut Registers<N, A>,
) -> Result<()> {
if self.operands.len() > N::MAX_INPUTS {
bail!("'{}' expects <= {} operands, found {} operands", Self::opcode(), N::MAX_INPUTS, self.operands.len())
}
let _inputs: Vec<_> = self.operands.iter().map(|operand| registers.load(stack, operand)).try_collect()?;
match VARIANT {
0 => {}
_ => bail!("Invalid 'finalize' variant: {VARIANT}"),
}
Ok(())
}
}
impl<N: Network, const VARIANT: u8> Parser for FinalizeOperation<N, VARIANT> {
#[inline]
fn parse(string: &str) -> ParserResult<Self> {
fn parse_operand<N: Network>(string: &str) -> ParserResult<Operand<N>> {
let (string, _) = Sanitizer::parse_whitespaces(string)?;
let (string, operand) = Operand::parse(string)?;
Ok((string, operand))
}
let (string, _) = Sanitizer::parse(string)?;
let (string, _) = tag(*Self::opcode())(string)?;
let (string, operands) = many0(parse_operand)(string)?;
let (string, _) = Sanitizer::parse(string)?;
let (string, _) = tag(";")(string)?;
Ok((string, Self { operands }))
}
}
impl<N: Network, const VARIANT: u8> FromStr for FinalizeOperation<N, VARIANT> {
type Err = Error;
#[inline]
fn from_str(string: &str) -> Result<Self> {
match Self::parse(string) {
Ok((remainder, object)) => {
ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
Ok(object)
}
Err(error) => bail!("Failed to parse string. {error}"),
}
}
}
impl<N: Network, const VARIANT: u8> Debug for FinalizeOperation<N, VARIANT> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Display::fmt(self, f)
}
}
impl<N: Network, const VARIANT: u8> Display for FinalizeOperation<N, VARIANT> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if self.operands.len() > N::MAX_INPUTS {
eprintln!("The number of operands must be <= {}, found {}", N::MAX_INPUTS, self.operands.len());
return Err(fmt::Error);
}
write!(f, "{}", Self::opcode())?;
self.operands.iter().try_for_each(|operand| write!(f, " {}", operand))?;
write!(f, ";")
}
}
impl<N: Network, const VARIANT: u8> FromBytes for FinalizeOperation<N, VARIANT> {
fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
let num_operands = u8::read_le(&mut reader)?;
if num_operands as usize > N::MAX_INPUTS {
return Err(error(format!("The number of operands must be <= {}, found {}", N::MAX_INPUTS, num_operands)));
}
let mut operands = Vec::with_capacity(num_operands as usize);
for _ in 0..(num_operands as usize) {
operands.push(Operand::read_le(&mut reader)?);
}
Ok(Self { operands })
}
}
impl<N: Network, const VARIANT: u8> ToBytes for FinalizeOperation<N, VARIANT> {
fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
if self.operands.len() > N::MAX_INPUTS {
return Err(error(format!(
"The number of operands must be <= {}, found {}",
N::MAX_INPUTS,
self.operands.len()
)));
}
(self.operands.len() as u8).write_le(&mut writer)?;
self.operands.iter().try_for_each(|operand| operand.write_le(&mut writer))
}
}
#[cfg(test)]
mod tests {
use super::*;
use console::network::Testnet3;
type CurrentNetwork = Testnet3;
#[test]
fn test_parse() {
let expected = "finalize r0 r1;";
let (string, finalize) = FinalizeCommand::<CurrentNetwork>::parse(expected).unwrap();
assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'");
assert_eq!(expected, finalize.to_string(), "Display.fmt() did not match expected: '{string}'");
assert_eq!(finalize.operands.len(), 2, "The number of operands is incorrect");
assert_eq!(finalize.operands[0], Operand::Register(Register::Locator(0)), "The first operand is incorrect");
assert_eq!(finalize.operands[1], Operand::Register(Register::Locator(1)), "The second operand is incorrect");
}
}