/ synthesizer / program / src / logic / command / remove.rs
remove.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::{network::prelude::*, program::Identifier};
 18  
 19  /// A remove command, e.g. `remove mapping[r0];`
 20  /// Removes the (`key`, `value`) entry in `mapping`.
 21  #[derive(Clone, PartialEq, Eq, Hash)]
 22  pub struct Remove<N: Network> {
 23      /// The mapping name.
 24      mapping: Identifier<N>,
 25      /// The operands
 26      operands: [Operand<N>; 1],
 27  }
 28  
 29  impl<N: Network> Remove<N> {
 30      /// Returns the opcode.
 31      #[inline]
 32      pub const fn opcode() -> Opcode {
 33          Opcode::Command("remove")
 34      }
 35  
 36      /// Returns the operands in the operation.
 37      #[inline]
 38      pub fn operands(&self) -> &[Operand<N>] {
 39          &self.operands
 40      }
 41  
 42      /// Returns the mapping name.
 43      #[inline]
 44      pub const fn mapping_name(&self) -> &Identifier<N> {
 45          &self.mapping
 46      }
 47  
 48      /// Returns the operand containing the key.
 49      #[inline]
 50      pub const fn key(&self) -> &Operand<N> {
 51          &self.operands[0]
 52      }
 53  }
 54  
 55  impl<N: Network> Remove<N> {
 56      /// Finalizes the command.
 57      pub fn finalize(
 58          &self,
 59          stack: &impl StackTrait<N>,
 60          store: &impl FinalizeStoreTrait<N>,
 61          registers: &mut impl RegistersTrait<N>,
 62      ) -> Result<Option<FinalizeOperation<N>>> {
 63          // Ensure the mapping exists.
 64          if !store.contains_mapping_speculative(stack.program_id(), &self.mapping)? {
 65              bail!("Mapping '{}/{}' does not exist", stack.program_id(), self.mapping);
 66          }
 67  
 68          // Load the key operand as a plaintext.
 69          let key = registers.load_plaintext(stack, self.key())?;
 70          // Update the value in storage, and return the finalize operation.
 71          store.remove_key_value(*stack.program_id(), self.mapping, &key)
 72      }
 73  }
 74  
 75  impl<N: Network> Parser for Remove<N> {
 76      /// Parses a string into an operation.
 77      fn parse(string: &str) -> ParserResult<Self> {
 78          // Parse the whitespace and comments from the string.
 79          let (string, _) = Sanitizer::parse(string)?;
 80          // Parse the opcode from the string.
 81          let (string, _) = tag(*Self::opcode())(string)?;
 82          // Parse the whitespace from the string.
 83          let (string, _) = Sanitizer::parse_whitespaces(string)?;
 84  
 85          // Parse the mapping name from the string.
 86          let (string, mapping) = Identifier::parse(string)?;
 87          // Parse the "[" from the string.
 88          let (string, _) = tag("[")(string)?;
 89          // Parse the whitespace from the string.
 90          let (string, _) = Sanitizer::parse_whitespaces(string)?;
 91          // Parse the key operand from the string.
 92          let (string, key) = Operand::parse(string)?;
 93          // Parse the whitespace from the string.
 94          let (string, _) = Sanitizer::parse_whitespaces(string)?;
 95          // Parse the "]" from the string.
 96          let (string, _) = tag("]")(string)?;
 97          // Parse the whitespace from the string.
 98          let (string, _) = Sanitizer::parse_whitespaces(string)?;
 99          // Parse the ";" from the string.
100          let (string, _) = tag(";")(string)?;
101  
102          Ok((string, Self { mapping, operands: [key] }))
103      }
104  }
105  
106  impl<N: Network> FromStr for Remove<N> {
107      type Err = Error;
108  
109      /// Parses a string into the command.
110      fn from_str(string: &str) -> Result<Self> {
111          match Self::parse(string) {
112              Ok((remainder, object)) => {
113                  // Ensure the remainder is empty.
114                  ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
115                  // Return the object.
116                  Ok(object)
117              }
118              Err(error) => bail!("Failed to parse string. {error}"),
119          }
120      }
121  }
122  
123  impl<N: Network> Debug for Remove<N> {
124      /// Prints the command as a string.
125      fn fmt(&self, f: &mut Formatter) -> fmt::Result {
126          Display::fmt(self, f)
127      }
128  }
129  
130  impl<N: Network> Display for Remove<N> {
131      /// Prints the command to a string.
132      fn fmt(&self, f: &mut Formatter) -> fmt::Result {
133          // Print the command, mapping, and key operand.
134          write!(f, "{} {}[{}];", Self::opcode(), self.mapping, self.key())
135      }
136  }
137  
138  impl<N: Network> FromBytes for Remove<N> {
139      /// Reads the command from a buffer.
140      fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
141          // Read the mapping name.
142          let mapping = Identifier::read_le(&mut reader)?;
143          // Read the key operand.
144          let key = Operand::read_le(&mut reader)?;
145          // Return the command.
146          Ok(Self { mapping, operands: [key] })
147      }
148  }
149  
150  impl<N: Network> ToBytes for Remove<N> {
151      /// Writes the operation to a buffer.
152      fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
153          // Write the mapping name.
154          self.mapping.write_le(&mut writer)?;
155          // Write the key operand.
156          self.key().write_le(&mut writer)
157      }
158  }
159  
160  #[cfg(test)]
161  mod tests {
162      use super::*;
163      use console::{network::MainnetV0, program::Register};
164  
165      type CurrentNetwork = MainnetV0;
166  
167      #[test]
168      fn test_parse() {
169          let (string, remove) = Remove::<CurrentNetwork>::parse("remove account[r1];").unwrap();
170          assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'");
171          assert_eq!(remove.mapping, Identifier::from_str("account").unwrap());
172          assert_eq!(remove.operands().len(), 1, "The number of operands is incorrect");
173          assert_eq!(remove.key(), &Operand::Register(Register::Locator(1)), "The first operand is incorrect");
174      }
175  }