snarkvm_console_program/data/future/
find.rs1use super::*;
17
18impl<N: Network> Future<N> {
19 pub fn find<A: Into<Access<N>> + Copy + Debug>(&self, path: &[A]) -> Result<Value<N>> {
21 ensure!(!path.is_empty(), "Attempted to find an argument with an empty path.");
23
24 enum ArgumentRefType<'a, N: Network> {
26 Plaintext(&'a Plaintext<N>),
28 Future(&'a Future<N>),
30 DynamicFuture(&'a DynamicFuture<N>),
32 }
33
34 let mut value = ArgumentRefType::Future(self);
36
37 for access in path.iter() {
39 let access = (*access).into();
40 match (value, access) {
41 (ArgumentRefType::Plaintext(Plaintext::Struct(members, ..)), Access::Member(identifier)) => {
42 match members.get(&identifier) {
43 Some(member) => value = ArgumentRefType::Plaintext(member),
45 None => bail!("Failed to locate member '{identifier}'"),
47 }
48 }
49 (ArgumentRefType::Plaintext(Plaintext::Array(array, ..)), Access::Index(index)) => {
50 match array.get(*index as usize) {
51 Some(element) => value = ArgumentRefType::Plaintext(element),
53 None => bail!("Index '{index}' is out of bounds"),
55 }
56 }
57 (ArgumentRefType::Future(future), Access::Index(index)) => {
58 match future.arguments.get(*index as usize) {
59 Some(Argument::Future(future)) => value = ArgumentRefType::Future(future),
61 Some(Argument::Plaintext(plaintext)) => value = ArgumentRefType::Plaintext(plaintext),
63 Some(Argument::DynamicFuture(dynamic_future)) => {
65 value = ArgumentRefType::DynamicFuture(dynamic_future)
66 }
67 None => bail!("Index '{index}' is out of bounds"),
69 }
70 }
71 _ => bail!("Invalid access `{access}`"),
72 }
73 }
74
75 match value {
76 ArgumentRefType::Plaintext(plaintext) => Ok(Value::Plaintext(plaintext.clone())),
77 ArgumentRefType::Future(future) => Ok(Value::Future(future.clone())),
78 ArgumentRefType::DynamicFuture(dynamic_future) => Ok(Value::DynamicFuture(dynamic_future.clone())),
79 }
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86 use snarkvm_console_network::MainnetV0;
87
88 use core::str::FromStr;
89
90 type CurrentNetwork = MainnetV0;
91
92 #[test]
93 fn test_find_plaintext_argument() {
94 let future = Future::<CurrentNetwork>::new(
96 ProgramID::from_str("test.aleo").unwrap(),
97 Identifier::from_str("foo").unwrap(),
98 vec![
99 Argument::Plaintext(Plaintext::from_str("100u64").unwrap()),
100 Argument::Plaintext(Plaintext::from_str("200u64").unwrap()),
101 ],
102 );
103
104 let value = future.find(&[Access::Index(U32::new(0))]).unwrap();
106 assert_eq!(value, Value::Plaintext(Plaintext::from_str("100u64").unwrap()));
107
108 let value = future.find(&[Access::Index(U32::new(1))]).unwrap();
110 assert_eq!(value, Value::Plaintext(Plaintext::from_str("200u64").unwrap()));
111 }
112
113 #[test]
114 fn test_find_nested_future_argument() {
115 let inner = Future::<CurrentNetwork>::new(
117 ProgramID::from_str("inner.aleo").unwrap(),
118 Identifier::from_str("bar").unwrap(),
119 vec![Argument::Plaintext(Plaintext::from_str("42u64").unwrap())],
120 );
121
122 let outer = Future::<CurrentNetwork>::new(
124 ProgramID::from_str("outer.aleo").unwrap(),
125 Identifier::from_str("baz").unwrap(),
126 vec![Argument::Future(inner.clone())],
127 );
128
129 let value = outer.find(&[Access::Index(U32::new(0))]).unwrap();
131 assert_eq!(value, Value::Future(inner));
132 }
133
134 #[test]
135 fn test_find_dynamic_future_argument() {
136 let inner = Future::<CurrentNetwork>::new(
138 ProgramID::from_str("inner.aleo").unwrap(),
139 Identifier::from_str("bar").unwrap(),
140 vec![Argument::Plaintext(Plaintext::from_str("42u64").unwrap())],
141 );
142 let dynamic_inner = DynamicFuture::from_future(&inner).unwrap();
143
144 let outer = Future::<CurrentNetwork>::new(
146 ProgramID::from_str("outer.aleo").unwrap(),
147 Identifier::from_str("baz").unwrap(),
148 vec![Argument::DynamicFuture(dynamic_inner.clone())],
149 );
150
151 let value = outer.find(&[Access::Index(U32::new(0))]).unwrap();
153
154 match value {
156 Value::DynamicFuture(result) => {
157 assert_eq!(result.program_name(), dynamic_inner.program_name());
158 assert_eq!(result.program_network(), dynamic_inner.program_network());
159 assert_eq!(result.function_name(), dynamic_inner.function_name());
160 assert_eq!(result.checksum(), dynamic_inner.checksum());
161 }
162 _ => panic!("Expected DynamicFuture value"),
163 }
164 }
165
166 #[test]
167 fn test_find_mixed_arguments() {
168 let inner = Future::<CurrentNetwork>::new(
170 ProgramID::from_str("inner.aleo").unwrap(),
171 Identifier::from_str("bar").unwrap(),
172 vec![],
173 );
174 let dynamic_inner = DynamicFuture::from_future(&inner).unwrap();
175
176 let future = Future::<CurrentNetwork>::new(
178 ProgramID::from_str("test.aleo").unwrap(),
179 Identifier::from_str("mixed").unwrap(),
180 vec![
181 Argument::Plaintext(Plaintext::from_str("100u64").unwrap()),
182 Argument::Future(inner.clone()),
183 Argument::DynamicFuture(dynamic_inner.clone()),
184 ],
185 );
186
187 let value = future.find(&[Access::Index(U32::new(0))]).unwrap();
189 assert!(matches!(value, Value::Plaintext(_)));
190
191 let value = future.find(&[Access::Index(U32::new(1))]).unwrap();
193 assert!(matches!(value, Value::Future(_)));
194
195 let value = future.find(&[Access::Index(U32::new(2))]).unwrap();
197 assert!(matches!(value, Value::DynamicFuture(_)));
198 }
199
200 #[test]
201 fn test_find_out_of_bounds() {
202 let future = Future::<CurrentNetwork>::new(
204 ProgramID::from_str("test.aleo").unwrap(),
205 Identifier::from_str("foo").unwrap(),
206 vec![Argument::Plaintext(Plaintext::from_str("100u64").unwrap())],
207 );
208
209 let result = future.find(&[Access::Index(U32::new(5))]);
211 assert!(result.is_err());
212 }
213
214 #[test]
215 fn test_dynamic_future_fields_cannot_be_accessed() {
216 let inner = Future::<CurrentNetwork>::new(
218 ProgramID::from_str("inner.aleo").unwrap(),
219 Identifier::from_str("bar").unwrap(),
220 vec![Argument::Plaintext(Plaintext::from_str("42u64").unwrap())],
221 );
222 let dynamic_inner = DynamicFuture::from_future(&inner).unwrap();
223
224 let outer = Future::<CurrentNetwork>::new(
226 ProgramID::from_str("outer.aleo").unwrap(),
227 Identifier::from_str("baz").unwrap(),
228 vec![Argument::DynamicFuture(dynamic_inner)],
229 );
230
231 let value = outer.find(&[Access::Index(U32::new(0))]).unwrap();
233 assert!(matches!(value, Value::DynamicFuture(_)));
234
235 let result = outer.find(&[Access::Index(U32::new(0)), Access::Index(U32::new(0))]);
238 assert!(result.is_err());
239 }
240}