defuse_near_utils/
promise.rs1use near_sdk::{Promise, env, json_types::U128, serde::de::DeserializeOwned, serde_json};
2
3pub trait PromiseExt: Sized {
4 fn and_maybe(self, p: Option<Promise>) -> Promise;
5}
6
7impl PromiseExt for Promise {
8 #[inline]
9 fn and_maybe(self, p: Option<Promise>) -> Promise {
10 if let Some(p) = p { self.and(p) } else { self }
11 }
12}
13
14pub type PromiseResult<T> = Result<T, near_sdk::PromiseError>;
15pub type PromiseJsonResult<T> = PromiseResult<Result<T, serde_json::Error>>;
16
17pub const MAX_JSON_LENGTH_RECURSION_LIMIT: usize = 32;
27
28pub trait MaxJsonLength: DeserializeOwned {
29 type Args;
30
31 fn max_json_length_root(args: Self::Args) -> usize {
32 Self::max_json_length_at(0, args)
33 }
34
35 fn max_json_length_at(depth: usize, args: Self::Args) -> usize;
36}
37
38#[inline]
39pub fn promise_result_checked_json_with_args<T: MaxJsonLength>(
40 result_idx: u64,
41 args: T::Args,
42) -> PromiseJsonResult<T> {
43 let value = env::promise_result_checked(result_idx, T::max_json_length_root(args))?;
44 Ok(serde_json::from_slice::<T>(&value))
45}
46
47#[inline]
48pub fn promise_result_checked_json<T: MaxJsonLength<Args = ()>>(
49 result_idx: u64,
50) -> PromiseJsonResult<T> {
51 promise_result_checked_json_with_args::<T>(result_idx, ())
52}
53
54#[inline]
55pub fn promise_result_checked_json_with_len<T: MaxJsonLength<Args = (usize, ())>>(
56 result_idx: u64,
57 length: usize,
58) -> PromiseJsonResult<T> {
59 let max_len = T::max_json_length_root((length, ()));
60 let value = env::promise_result_checked(result_idx, max_len)?;
61 Ok(serde_json::from_slice::<T>(&value))
62}
63
64#[inline]
68pub fn promise_result_checked_void(result_idx: u64) -> PromiseResult<()> {
69 let data = env::promise_result_checked(result_idx, 0)?;
70 debug_assert!(data.is_empty());
71 Ok(())
72}
73
74impl MaxJsonLength for bool {
75 type Args = ();
76
77 fn max_json_length_at(_depth: usize, _args: ()) -> usize {
78 " false ".len()
79 }
80}
81
82impl MaxJsonLength for U128 {
83 type Args = ();
84
85 fn max_json_length_at(_depth: usize, _args: ()) -> usize {
86 " \"\" ".len() + "+340282366920938463463374607431768211455".len()
87 }
88}
89
90impl<T> MaxJsonLength for Vec<T>
91where
92 T: MaxJsonLength,
93{
94 type Args = (usize, T::Args);
95
96 fn max_json_length_at(depth: usize, (length, item_args): (usize, T::Args)) -> usize {
97 const INDENT_STEP: usize = " ".len();
98
99 if depth >= MAX_JSON_LENGTH_RECURSION_LIMIT {
100 return usize::MAX;
101 }
102
103 let ident = INDENT_STEP.saturating_mul(depth);
104 let item_indent = ident.saturating_add(INDENT_STEP);
105
106 item_indent
107 .saturating_add(T::max_json_length_at(depth + 1, item_args))
108 .saturating_add(",\n".len())
109 .saturating_mul(length)
110 .saturating_add(" [\n] ".len() + ident)
111 }
112}
113
114impl<T, const N: usize> MaxJsonLength for [T; N]
115where
116 T: MaxJsonLength,
117 Self: DeserializeOwned,
118{
119 type Args = T::Args;
120
121 fn max_json_length_at(depth: usize, args: Self::Args) -> usize {
122 <Vec<T>>::max_json_length_at(depth, (N, args))
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use near_sdk::json_types::U128;
129 use rstest::rstest;
130
131 use super::*;
132
133 #[test]
134 fn test_max_bool_json_len() {
135 let max_len = bool::max_json_length_root(());
136
137 let prettified_false = serde_json::to_string_pretty(&false).unwrap();
138 let prettified_true = serde_json::to_string_pretty(&true).unwrap();
139 assert!(prettified_false.len() <= max_len);
140 assert!(prettified_true.len() <= max_len);
141
142 let compact_false = serde_json::to_string(&false).unwrap();
143 let compact_true = serde_json::to_string(&true).unwrap();
144 assert!(compact_false.len() <= max_len);
145 assert!(compact_true.len() <= max_len);
146 }
147
148 #[test]
149 fn test_max_u128_json_len() {
150 let max_len = U128::max_json_length_root(());
151
152 let max_val = U128(u128::MAX);
153 let prettified = serde_json::to_string_pretty(&max_val).unwrap();
154 assert!(prettified.len() <= max_len);
155
156 let compact = serde_json::to_string(&max_val).unwrap();
157 assert!(compact.len() <= max_len);
158 }
159
160 #[rstest]
161 #[case::len_0(0)]
162 #[case::len_1(1)]
163 #[case::len_2(2)]
164 #[case::len_5(5)]
165 #[case::len_10(10)]
166 #[case::len_100(100)]
167 fn test_max_vec_u128_json_len(#[case] count: usize) {
168 let max_len = Vec::<U128>::max_json_length_root((count, ()));
169
170 let vec: Vec<U128> = vec![U128(u128::MAX); count];
171 let prettified = serde_json::to_string_pretty(&vec).unwrap();
172 assert!(prettified.len() <= max_len);
173
174 let compact = serde_json::to_string(&vec).unwrap();
175 assert!(compact.len() <= max_len);
176 }
177
178 #[rstest]
179 #[case::outer_1_inner_3(1, 3)]
180 #[case::outer_3_inner_5(3, 5)]
181 #[case::outer_5_inner_10(5, 10)]
182 fn test_max_nested_vec_u128_json_len(#[case] outer: usize, #[case] inner: usize) {
183 let max_len = Vec::<Vec<U128>>::max_json_length_at(0, (outer, (inner, ())));
184
185 let vec: Vec<Vec<U128>> = vec![vec![U128(u128::MAX); inner]; outer];
186 let prettified = serde_json::to_string_pretty(&vec).unwrap();
187 assert!(prettified.len() <= max_len);
188
189 let compact = serde_json::to_string(&vec).unwrap();
190 assert!(compact.len() <= max_len);
191 }
192
193 #[test]
194 fn test_max_array_u128_json_len() {
195 let max_len = <[U128; 5]>::max_json_length_root(());
196
197 let arr = [U128(u128::MAX); 5];
198 let prettified = serde_json::to_string_pretty(&arr).unwrap();
199 assert!(prettified.len() <= max_len);
200
201 let compact = serde_json::to_string(&arr).unwrap();
202 assert!(compact.len() <= max_len);
203 }
204
205 #[test]
206 fn test_depth_exceeds_limit_returns_max() {
207 assert_eq!(
208 Vec::<U128>::max_json_length_at(MAX_JSON_LENGTH_RECURSION_LIMIT + 1, (10, ())),
209 usize::MAX,
210 );
211 }
212}