get_or_use.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::{CallOperator, FinalizeStoreTrait, Opcode, Operand, RegistersTrait, StackTrait}; 17 use console::{ 18 network::prelude::*, 19 program::{Register, Value}, 20 }; 21 22 /// A get command that uses the provided default in case of failure, e.g. `get.or_use accounts[r0] r1 into r2;`. 23 /// Gets the value stored at `operand` in `mapping` and stores the result in `destination`. 24 /// If the key is not present, `default` is stored in `destination`. 25 #[derive(Clone, PartialEq, Eq, Hash)] 26 pub struct GetOrUse<N: Network> { 27 /// The mapping. 28 mapping: CallOperator<N>, 29 /// The operands. 30 operands: [Operand<N>; 2], 31 /// The destination register. 32 destination: Register<N>, 33 } 34 35 impl<N: Network> GetOrUse<N> { 36 /// Returns the opcode. 37 #[inline] 38 pub const fn opcode() -> Opcode { 39 Opcode::Command("get.or_use") 40 } 41 42 /// Returns the operands in the operation. 43 #[inline] 44 pub fn operands(&self) -> &[Operand<N>] { 45 &self.operands 46 } 47 48 /// Returns the mapping. 49 #[inline] 50 pub const fn mapping(&self) -> &CallOperator<N> { 51 &self.mapping 52 } 53 54 /// Returns the operand containing the key. 55 #[inline] 56 pub const fn key(&self) -> &Operand<N> { 57 &self.operands[0] 58 } 59 60 /// Returns the default value. 61 #[inline] 62 pub const fn default(&self) -> &Operand<N> { 63 &self.operands[1] 64 } 65 66 /// Returns the destination register. 67 #[inline] 68 pub const fn destination(&self) -> &Register<N> { 69 &self.destination 70 } 71 } 72 73 impl<N: Network> GetOrUse<N> { 74 /// Finalizes the command. 75 #[inline] 76 pub fn finalize( 77 &self, 78 stack: &impl StackTrait<N>, 79 store: &impl FinalizeStoreTrait<N>, 80 registers: &mut impl RegistersTrait<N>, 81 ) -> Result<()> { 82 // Determine the program ID and mapping name. 83 let (program_id, mapping_name) = match self.mapping { 84 CallOperator::Locator(locator) => (*locator.program_id(), *locator.resource()), 85 CallOperator::Resource(mapping_name) => (*stack.program_id(), mapping_name), 86 }; 87 88 // Ensure the mapping exists. 89 if !store.contains_mapping_speculative(&program_id, &mapping_name)? { 90 bail!("Mapping '{program_id}/{mapping_name}' does not exist"); 91 } 92 93 // Load the operand as a plaintext. 94 let key = registers.load_plaintext(stack, self.key())?; 95 96 // Retrieve the value from storage as a literal. 97 let value = match store.get_value_speculative(program_id, mapping_name, &key)? { 98 Some(Value::Plaintext(plaintext)) => Value::Plaintext(plaintext), 99 Some(Value::Record(..)) => bail!("Cannot 'get.or_use' a 'record'"), 100 Some(Value::Future(..)) => bail!("Cannot 'get.or_use' a 'future'"), 101 // If a key does not exist, then use the default value. 102 None => Value::Plaintext(registers.load_plaintext(stack, self.default())?), 103 }; 104 105 // Assign the value to the destination register. 106 registers.store(stack, &self.destination, value)?; 107 108 // Return the finalize operation. 109 Ok(()) 110 } 111 } 112 113 impl<N: Network> Parser for GetOrUse<N> { 114 /// Parses a string into an operation. 115 #[inline] 116 fn parse(string: &str) -> ParserResult<Self> { 117 // Parse the whitespace and comments from the string. 118 let (string, _) = Sanitizer::parse(string)?; 119 // Parse the opcode from the string. 120 let (string, _) = tag(*Self::opcode())(string)?; 121 // Parse the whitespace from the string. 122 let (string, _) = Sanitizer::parse_whitespaces(string)?; 123 124 // Parse the mapping name from the string. 125 let (string, mapping) = CallOperator::parse(string)?; 126 // Parse the "[" from the string. 127 let (string, _) = tag("[")(string)?; 128 // Parse the whitespace from the string. 129 let (string, _) = Sanitizer::parse_whitespaces(string)?; 130 // Parse the key operand from the string. 131 let (string, key) = Operand::parse(string)?; 132 // Parse the whitespace from the string. 133 let (string, _) = Sanitizer::parse_whitespaces(string)?; 134 // Parse the "]" from the string. 135 let (string, _) = tag("]")(string)?; 136 // Parse the whitespace from the string. 137 let (string, _) = Sanitizer::parse_whitespaces(string)?; 138 // Parse the default value from the string. 139 let (string, default) = Operand::parse(string)?; 140 141 // Parse the whitespace from the string. 142 let (string, _) = Sanitizer::parse_whitespaces(string)?; 143 // Parse the "into" keyword from the string. 144 let (string, _) = tag("into")(string)?; 145 // Parse the whitespace from the string. 146 let (string, _) = Sanitizer::parse_whitespaces(string)?; 147 // Parse the destination register from the string. 148 let (string, destination) = Register::parse(string)?; 149 150 // Parse the whitespace from the string. 151 let (string, _) = Sanitizer::parse_whitespaces(string)?; 152 // Parse the ";" from the string. 153 let (string, _) = tag(";")(string)?; 154 155 Ok((string, Self { mapping, operands: [key, default], destination })) 156 } 157 } 158 159 impl<N: Network> FromStr for GetOrUse<N> { 160 type Err = Error; 161 162 /// Parses a string into the command. 163 #[inline] 164 fn from_str(string: &str) -> Result<Self> { 165 match Self::parse(string) { 166 Ok((remainder, object)) => { 167 // Ensure the remainder is empty. 168 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\""); 169 // Return the object. 170 Ok(object) 171 } 172 Err(error) => bail!("Failed to parse string. {error}"), 173 } 174 } 175 } 176 177 impl<N: Network> Debug for GetOrUse<N> { 178 /// Prints the command as a string. 179 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 180 Display::fmt(self, f) 181 } 182 } 183 184 impl<N: Network> Display for GetOrUse<N> { 185 /// Prints the command to a string. 186 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 187 // Print the command. 188 write!(f, "{} ", Self::opcode())?; 189 // Print the mapping and key operand. 190 write!(f, "{}[{}] {} into ", self.mapping, self.key(), self.default())?; 191 // Print the destination register. 192 write!(f, "{};", self.destination) 193 } 194 } 195 196 impl<N: Network> FromBytes for GetOrUse<N> { 197 /// Reads the command from a buffer. 198 fn read_le<R: Read>(mut reader: R) -> IoResult<Self> { 199 // Read the mapping name. 200 let mapping = CallOperator::read_le(&mut reader)?; 201 // Read the key operand. 202 let key = Operand::read_le(&mut reader)?; 203 // Read the default value. 204 let default = Operand::read_le(&mut reader)?; 205 // Read the destination register. 206 let destination = Register::read_le(&mut reader)?; 207 // Return the command. 208 Ok(Self { mapping, operands: [key, default], destination }) 209 } 210 } 211 212 impl<N: Network> ToBytes for GetOrUse<N> { 213 /// Writes the operation to a buffer. 214 fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> { 215 // Write the mapping name. 216 self.mapping.write_le(&mut writer)?; 217 // Write the key operand. 218 self.key().write_le(&mut writer)?; 219 // Write the default value. 220 self.default().write_le(&mut writer)?; 221 // Write the destination register. 222 self.destination.write_le(&mut writer) 223 } 224 } 225 226 #[cfg(test)] 227 mod tests { 228 use super::*; 229 use console::{network::MainnetV0, program::Register}; 230 231 type CurrentNetwork = MainnetV0; 232 233 #[test] 234 fn test_parse() { 235 let (string, get_or_use) = GetOrUse::<CurrentNetwork>::parse("get.or_use account[r0] r1 into r2;").unwrap(); 236 assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'"); 237 assert_eq!(get_or_use.mapping, CallOperator::from_str("account").unwrap()); 238 assert_eq!(get_or_use.operands().len(), 2, "The number of operands is incorrect"); 239 assert_eq!(get_or_use.key(), &Operand::Register(Register::Locator(0)), "The first operand is incorrect"); 240 assert_eq!(get_or_use.default(), &Operand::Register(Register::Locator(1)), "The second operand is incorrect"); 241 assert_eq!(get_or_use.destination, Register::Locator(2), "The second operand is incorrect"); 242 243 let (string, get_or_use) = 244 GetOrUse::<CurrentNetwork>::parse("get.or_use token.alpha/balances[r0] r1 into r2;").unwrap(); 245 assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'"); 246 assert_eq!(get_or_use.mapping, CallOperator::from_str("token.alpha/balances").unwrap()); 247 assert_eq!(get_or_use.operands().len(), 2, "The number of operands is incorrect"); 248 assert_eq!(get_or_use.key(), &Operand::Register(Register::Locator(0)), "The first operand is incorrect"); 249 assert_eq!(get_or_use.default(), &Operand::Register(Register::Locator(1)), "The second operand is incorrect"); 250 assert_eq!(get_or_use.destination, Register::Locator(2), "The second operand is incorrect"); 251 } 252 253 #[test] 254 fn test_from_bytes() { 255 let (string, get_or_use) = GetOrUse::<CurrentNetwork>::parse("get.or_use account[r0] r1 into r2;").unwrap(); 256 assert!(string.is_empty()); 257 let bytes_le = get_or_use.to_bytes_le().unwrap(); 258 let result = GetOrUse::<CurrentNetwork>::from_bytes_le(&bytes_le[..]); 259 assert!(result.is_ok()); 260 } 261 }