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 }