1use crate::{contract_def::Argument, prelude::*, ContractEnv};
4use casper_types::{
5 bytesrepr::{FromBytes, ToBytes},
6 CLType, CLTyped, Parameter, RuntimeArgs
7};
8
9#[derive(Default, Debug, Clone)]
11pub enum Maybe<T> {
12 Some(T),
14 #[default]
16 None
17}
18
19impl<T> Maybe<T> {
20 pub fn is_some(&self) -> bool {
22 matches!(self, Maybe::Some(_))
23 }
24
25 pub fn is_none(&self) -> bool {
27 matches!(self, Maybe::None)
28 }
29
30 pub fn unwrap(self, env: &ContractEnv) -> T {
33 match self {
34 Maybe::Some(value) => value,
35 Maybe::None => env.revert(ExecutionError::UnwrapError)
36 }
37 }
38
39 pub fn unwrap_or(self, default: T) -> T {
41 match self {
42 Maybe::Some(value) => value,
43 Maybe::None => default
44 }
45 }
46}
47
48impl<T: Default> Maybe<T> {
49 pub fn unwrap_or_default(self) -> T {
51 match self {
52 Maybe::Some(value) => value,
53 Maybe::None => T::default()
54 }
55 }
56}
57
58impl<T: ToBytes> ToBytes for Maybe<T> {
59 fn to_bytes(&self) -> Result<Vec<u8>, casper_types::bytesrepr::Error> {
60 match self {
61 Maybe::Some(value) => value.to_bytes(),
62 Maybe::None => Ok(Vec::new())
63 }
64 }
65
66 fn serialized_length(&self) -> usize {
67 match self {
68 Maybe::Some(value) => value.serialized_length(),
69 Maybe::None => 0
70 }
71 }
72}
73
74impl<T: FromBytes> FromBytes for Maybe<T> {
75 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), casper_types::bytesrepr::Error> {
76 let res = T::from_bytes(bytes);
77 if let Ok((value, rem)) = res {
78 Ok((Maybe::Some(value), rem))
79 } else {
80 Ok((Maybe::None, bytes))
81 }
82 }
83
84 fn from_vec(bytes: Vec<u8>) -> Result<(Self, Vec<u8>), casper_types::bytesrepr::Error> {
85 Self::from_bytes(bytes.as_slice()).map(|(x, remainder)| (x, Vec::from(remainder)))
86 }
87}
88
89pub trait EntrypointArgument: Sized {
91 fn is_required() -> bool;
93 fn cl_type() -> CLType;
95 fn insert_runtime_arg(self, name: &str, args: &mut RuntimeArgs);
97 fn unwrap(value: Option<Self>, env: &ContractEnv) -> Self;
99}
100
101impl<T: CLTyped + ToBytes> EntrypointArgument for Maybe<T> {
102 fn is_required() -> bool {
103 false
104 }
105
106 fn cl_type() -> CLType {
107 T::cl_type()
108 }
109
110 fn insert_runtime_arg(self, name: &str, args: &mut RuntimeArgs) {
111 if let Maybe::Some(v) = self {
112 let _ = args.insert(name, v);
113 }
114 }
115
116 fn unwrap(value: Option<Self>, _env: &ContractEnv) -> Self {
117 match value {
118 Some(v) => v,
119 None => Maybe::None
120 }
121 }
122}
123
124impl<T: CLTyped + ToBytes> EntrypointArgument for T {
125 fn is_required() -> bool {
126 true
127 }
128
129 fn cl_type() -> CLType {
130 T::cl_type()
131 }
132
133 fn insert_runtime_arg(self, name: &str, args: &mut RuntimeArgs) {
134 let _ = args.insert(name, self);
135 }
136
137 fn unwrap(value: Option<Self>, env: &ContractEnv) -> Self {
138 match value {
139 Some(v) => v,
140 None => env.revert(ExecutionError::UnwrapError)
141 }
142 }
143}
144
145pub fn parameter<T: EntrypointArgument>(name: &str) -> Option<Parameter> {
148 match T::is_required() {
149 true => Some(Parameter::new(name, T::cl_type())),
150 false => None
151 }
152}
153
154pub fn odra_argument<T: EntrypointArgument>(name: &str) -> Argument {
156 Argument {
157 name: name.to_string(),
158 ty: T::cl_type(),
159 is_ref: false,
160 is_slice: false,
161 is_required: T::is_required()
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168 use crate::contract_context::MockContractContext;
169 use casper_types::U256;
170
171 #[test]
172 fn test_maybe() {
173 let some = Maybe::Some(1);
174 let none: Maybe<u32> = Maybe::None;
175
176 let ctx = MockContractContext::new();
177 let env = ContractEnv::new(0, Rc::new(RefCell::new(ctx)));
178
179 assert!(some.is_some());
180 assert!(!some.is_none());
181 assert_eq!(some.clone().unwrap(&env), 1);
182 assert_eq!(some.unwrap_or_default(), 1);
183
184 assert!(!none.is_some());
185 assert!(none.is_none());
186 assert_eq!(none.unwrap_or_default(), 0);
187 }
188
189 #[test]
190 #[should_panic(expected = "revert")]
191 fn unwrap_on_none() {
192 let none: Maybe<u32> = Maybe::None;
193 let mut ctx = MockContractContext::new();
194 ctx.expect_revert().returning(|_| panic!("revert"));
195 let env = ContractEnv::new(0, Rc::new(RefCell::new(ctx)));
196
197 none.unwrap(&env);
198 }
199
200 #[test]
201 fn test_into_args() {
202 let args = [
203 odra_argument::<Maybe<u32>>("arg1"),
204 odra_argument::<U256>("arg2"),
205 odra_argument::<Option<String>>("arg3")
206 ];
207
208 assert_eq!(args.len(), 3);
209 }
210
211 #[test]
212 fn test_into_casper_parameters() {
213 let params = [
214 parameter::<Maybe<u32>>("arg1"),
215 parameter::<Option<u32>>("arg2"),
216 parameter::<Maybe<Option<u32>>>("arg3"),
217 parameter::<Address>("arg4")
218 ]
219 .into_iter()
220 .flatten()
221 .collect::<Vec<_>>();
222
223 assert_eq!(params.len(), 2);
224 }
225}