find.rs
1 // Copyright (c) 2019-2025 Alpha-Delta Network Inc. 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 super::*; 17 18 impl<N: Network> Future<N> { 19 /// Returns a value from the given path. 20 pub fn find<A: Into<Access<N>> + Copy + Debug>(&self, path: &[A]) -> Result<Value<N>> { 21 // Ensure the path is not empty. 22 ensure!(!path.is_empty(), "Attempted to find an argument with an empty path."); 23 24 // A helper enum to track the the argument. 25 enum ArgumentRefType<'a, N: Network> { 26 /// A plaintext type. 27 Plaintext(&'a Plaintext<N>), 28 /// A future. 29 Future(&'a Future<N>), 30 } 31 32 // Initialize a value starting from the top-level. 33 let mut value = ArgumentRefType::Future(self); 34 35 // Iterate through the path to retrieve the value. 36 for access in path.iter() { 37 let access = (*access).into(); 38 match (value, access) { 39 (ArgumentRefType::Plaintext(Plaintext::Struct(members, ..)), Access::Member(identifier)) => { 40 match members.get(&identifier) { 41 // Retrieve the member and update `value` for the next iteration. 42 Some(member) => value = ArgumentRefType::Plaintext(member), 43 // Halts if the member does not exist. 44 None => bail!("Failed to locate member '{identifier}'"), 45 } 46 } 47 (ArgumentRefType::Plaintext(Plaintext::Array(array, ..)), Access::Index(index)) => { 48 match array.get(*index as usize) { 49 // Retrieve the element and update `value` for the next iteration. 50 Some(element) => value = ArgumentRefType::Plaintext(element), 51 // Halts if the index is out of bounds. 52 None => bail!("Index '{index}' is out of bounds"), 53 } 54 } 55 (ArgumentRefType::Future(future), Access::Index(index)) => { 56 match future.arguments.get(*index as usize) { 57 // If the argument is a future, update `value` for the next iteration. 58 Some(Argument::Future(future)) => value = ArgumentRefType::Future(future), 59 // If the argument is a plaintext, update `value` for the next iteration. 60 Some(Argument::Plaintext(plaintext)) => value = ArgumentRefType::Plaintext(plaintext), 61 // Halts if the index is out of bounds. 62 None => bail!("Index '{index}' is out of bounds"), 63 } 64 } 65 _ => bail!("Invalid access `{access}`"), 66 } 67 } 68 69 match value { 70 ArgumentRefType::Plaintext(plaintext) => Ok(Value::Plaintext(plaintext.clone())), 71 ArgumentRefType::Future(future) => Ok(Value::Future(future.clone())), 72 } 73 } 74 }