find.rs
1 // Copyright (c) 2019-2025 Alpha-Delta Network Inc. 2 // This file is part of the deltavm 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<A: Alpha> Future<A> { 19 /// Returns the value from the given path. 20 pub fn find<A0: Into<Access<A>> + Clone + Debug>(&self, path: &[A0]) -> Result<Value<A>> { 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, A: Alpha> { 26 /// A plaintext type. 27 Plaintext(&'a Plaintext<A>), 28 /// A future. 29 Future(&'a Future<A>), 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.clone().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 let index = match index.eject_mode() { 49 Mode::Constant => index.eject_value(), 50 _ => bail!("'{index}' must be a constant"), 51 }; 52 match array.get(*index as usize) { 53 // Retrieve the element and update `value` for the next iteration. 54 Some(element) => value = ArgumentRefType::Plaintext(element), 55 // Halts if the index is out of bounds. 56 None => bail!("Index '{index}' is out of bounds"), 57 } 58 } 59 (ArgumentRefType::Future(future), Access::Index(index)) => { 60 let index = match index.eject_mode() { 61 Mode::Constant => index.eject_value(), 62 _ => bail!("'{index}' must be a constant"), 63 }; 64 match future.arguments.get(*index as usize) { 65 // If the argument is a future, update `value` for the next iteration. 66 Some(Argument::Future(future)) => value = ArgumentRefType::Future(future), 67 // If the argument is a plaintext, update `value` for the next iteration. 68 Some(Argument::Plaintext(plaintext)) => value = ArgumentRefType::Plaintext(plaintext), 69 // Halts if the index is out of bounds. 70 None => bail!("Index '{index}' is out of bounds"), 71 } 72 } 73 _ => bail!("Invalid access `{access}`"), 74 } 75 } 76 77 match value { 78 ArgumentRefType::Plaintext(plaintext) => Ok(Value::Plaintext(plaintext.clone())), 79 ArgumentRefType::Future(future) => Ok(Value::Future(future.clone())), 80 } 81 } 82 }