set.rs
  1  // Copyright (c) 2025 ADnet Contributors
  2  // This file is part of the AlphaVM library.
  3  
  4  // Licensed under the Apache License, Version 2.0 (the "License");
  5  // you may not use this file except in compliance with the License.
  6  // You may obtain a copy of the License at:
  7  
  8  // http://www.apache.org/licenses/LICENSE-2.0
  9  
 10  // Unless required by applicable law or agreed to in writing, software
 11  // distributed under the License is distributed on an "AS IS" BASIS,
 12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  // See the License for the specific language governing permissions and
 14  // limitations under the License.
 15  
 16  use crate::{FinalizeOperation, FinalizeStoreTrait, Opcode, Operand, RegistersTrait, StackTrait};
 17  use console::{
 18      network::prelude::*,
 19      program::{Identifier, Value},
 20  };
 21  
 22  /// A set command, e.g. `set r1 into mapping[r0];`
 23  /// Sets the `key` entry as `value` in `mapping`.
 24  #[derive(Clone, PartialEq, Eq, Hash)]
 25  pub struct Set<N: Network> {
 26      /// The mapping name.
 27      mapping: Identifier<N>,
 28      /// The operands.
 29      operands: [Operand<N>; 2],
 30  }
 31  
 32  impl<N: Network> Set<N> {
 33      /// Returns the opcode.
 34      #[inline]
 35      pub const fn opcode() -> Opcode {
 36          Opcode::Command("set")
 37      }
 38  
 39      /// Returns the operands in the operation.
 40      #[inline]
 41      pub fn operands(&self) -> &[Operand<N>] {
 42          &self.operands
 43      }
 44  
 45      /// Returns the mapping name.
 46      #[inline]
 47      pub const fn mapping_name(&self) -> &Identifier<N> {
 48          &self.mapping
 49      }
 50  
 51      /// Returns the operand containing the key.
 52      #[inline]
 53      pub const fn key(&self) -> &Operand<N> {
 54          &self.operands[0]
 55      }
 56  
 57      /// Returns the operand containing the value.
 58      #[inline]
 59      pub const fn value(&self) -> &Operand<N> {
 60          &self.operands[1]
 61      }
 62  }
 63  
 64  impl<N: Network> Set<N> {
 65      /// Finalizes the command.
 66      pub fn finalize(
 67          &self,
 68          stack: &impl StackTrait<N>,
 69          store: &impl FinalizeStoreTrait<N>,
 70          registers: &mut impl RegistersTrait<N>,
 71      ) -> Result<FinalizeOperation<N>> {
 72          // Ensure the mapping exists.
 73          if !store.contains_mapping_speculative(stack.program_id(), &self.mapping)? {
 74              bail!("Mapping '{}/{}' does not exist", stack.program_id(), self.mapping);
 75          }
 76  
 77          // Load the key operand as a plaintext.
 78          let key = registers.load_plaintext(stack, self.key())?;
 79          // Load the value operand as a plaintext.
 80          let value = Value::Plaintext(registers.load_plaintext(stack, self.value())?);
 81  
 82          // Update the value in storage, and return the finalize operation.
 83          store.update_key_value(*stack.program_id(), self.mapping, key, value)
 84      }
 85  }
 86  
 87  impl<N: Network> Parser for Set<N> {
 88      /// Parses a string into an operation.
 89      fn parse(string: &str) -> ParserResult<Self> {
 90          // Parse the whitespace and comments from the string.
 91          let (string, _) = Sanitizer::parse(string)?;
 92          // Parse the opcode from the string.
 93          let (string, _) = tag(*Self::opcode())(string)?;
 94          // Parse the whitespace from the string.
 95          let (string, _) = Sanitizer::parse_whitespaces(string)?;
 96  
 97          // Parse the value operand from the string.
 98          let (string, value) = Operand::parse(string)?;
 99          // Parse the whitespace from the string.
100          let (string, _) = Sanitizer::parse_whitespaces(string)?;
101  
102          // Parse the "into" keyword from the string.
103          let (string, _) = tag("into")(string)?;
104          // Parse the whitespace from the string.
105          let (string, _) = Sanitizer::parse_whitespaces(string)?;
106  
107          // Parse the mapping name from the string.
108          let (string, mapping) = Identifier::parse(string)?;
109          // Parse the "[" from the string.
110          let (string, _) = tag("[")(string)?;
111          // Parse the whitespace from the string.
112          let (string, _) = Sanitizer::parse_whitespaces(string)?;
113          // Parse the key operand from the string.
114          let (string, key) = Operand::parse(string)?;
115          // Parse the whitespace from the string.
116          let (string, _) = Sanitizer::parse_whitespaces(string)?;
117          // Parse the "]" from the string.
118          let (string, _) = tag("]")(string)?;
119          // Parse the whitespace from the string.
120          let (string, _) = Sanitizer::parse_whitespaces(string)?;
121          // Parse the ";" from the string.
122          let (string, _) = tag(";")(string)?;
123  
124          Ok((string, Self { mapping, operands: [key, value] }))
125      }
126  }
127  
128  impl<N: Network> FromStr for Set<N> {
129      type Err = Error;
130  
131      /// Parses a string into the command.
132      #[inline]
133      fn from_str(string: &str) -> Result<Self> {
134          match Self::parse(string) {
135              Ok((remainder, object)) => {
136                  // Ensure the remainder is empty.
137                  ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
138                  // Return the object.
139                  Ok(object)
140              }
141              Err(error) => bail!("Failed to parse string. {error}"),
142          }
143      }
144  }
145  
146  impl<N: Network> Debug for Set<N> {
147      /// Prints the command as a string.
148      fn fmt(&self, f: &mut Formatter) -> fmt::Result {
149          Display::fmt(self, f)
150      }
151  }
152  
153  impl<N: Network> Display for Set<N> {
154      /// Prints the command to a string.
155      fn fmt(&self, f: &mut Formatter) -> fmt::Result {
156          // Print the command.
157          write!(f, "{} ", Self::opcode())?;
158          // Print the value operand.
159          write!(f, "{} into ", self.value())?;
160          // Print the mapping and key operand.
161          write!(f, "{}[{}];", self.mapping, self.key())
162      }
163  }
164  
165  impl<N: Network> FromBytes for Set<N> {
166      /// Reads the command from a buffer.
167      fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
168          // Read the mapping name.
169          let mapping = Identifier::read_le(&mut reader)?;
170          // Read the key operand.
171          let key = Operand::read_le(&mut reader)?;
172          // Read the value operand.
173          let value = Operand::read_le(&mut reader)?;
174          // Return the command.
175          Ok(Self { mapping, operands: [key, value] })
176      }
177  }
178  
179  impl<N: Network> ToBytes for Set<N> {
180      /// Writes the operation to a buffer.
181      fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
182          // Write the mapping name.
183          self.mapping.write_le(&mut writer)?;
184          // Write the key operand.
185          self.key().write_le(&mut writer)?;
186          // Write the value operand.
187          self.value().write_le(&mut writer)
188      }
189  }
190  
191  #[cfg(test)]
192  mod tests {
193      use super::*;
194      use console::{network::MainnetV0, program::Register};
195  
196      type CurrentNetwork = MainnetV0;
197  
198      #[test]
199      fn test_parse() {
200          let (string, set) = Set::<CurrentNetwork>::parse("set r0 into account[r1];").unwrap();
201          assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'");
202          assert_eq!(set.mapping, Identifier::from_str("account").unwrap());
203          assert_eq!(set.operands().len(), 2, "The number of operands is incorrect");
204          assert_eq!(set.value(), &Operand::Register(Register::Locator(0)), "The first operand is incorrect");
205          assert_eq!(set.key(), &Operand::Register(Register::Locator(1)), "The second operand is incorrect");
206      }
207  }