1use std::time::Duration;
2
3use crate::SorobanHelperError;
4use stellar_xdr::curr::{
5 AccountId, BytesM, Duration as XDRDuration, ScAddress, ScBytes, ScString, ScVal, ScVec,
6 StringM, VecM,
7};
8
9pub trait IntoScVal {
11 fn try_into_val(&self) -> Result<ScVal, SorobanHelperError>;
12 fn into_val(self) -> ScVal;
13}
14
15impl IntoScVal for AccountId {
17 fn try_into_val(&self) -> Result<ScVal, SorobanHelperError> {
18 Ok(ScVal::Address(ScAddress::Account(self.clone())))
19 }
20
21 fn into_val(self) -> ScVal {
22 ScVal::Address(ScAddress::Account(self))
23 }
24}
25
26impl IntoScVal for u32 {
28 fn try_into_val(&self) -> Result<ScVal, SorobanHelperError> {
29 Ok(ScVal::U32(*self))
30 }
31
32 fn into_val(self) -> ScVal {
33 ScVal::U32(self)
34 }
35}
36
37impl IntoScVal for u64 {
39 fn try_into_val(&self) -> Result<ScVal, SorobanHelperError> {
40 Ok(ScVal::U64(*self))
41 }
42
43 fn into_val(self) -> ScVal {
44 ScVal::U64(self)
45 }
46}
47
48impl IntoScVal for i32 {
50 fn try_into_val(&self) -> Result<ScVal, SorobanHelperError> {
51 Ok(ScVal::I32(*self))
52 }
53
54 fn into_val(self) -> ScVal {
55 ScVal::I32(self)
56 }
57}
58
59impl IntoScVal for i64 {
61 fn try_into_val(&self) -> Result<ScVal, SorobanHelperError> {
62 Ok(ScVal::I64(*self))
63 }
64
65 fn into_val(self) -> ScVal {
66 ScVal::I64(self)
67 }
68}
69
70impl IntoScVal for bool {
72 fn try_into_val(&self) -> Result<ScVal, SorobanHelperError> {
73 Ok(ScVal::Bool(*self))
74 }
75
76 fn into_val(self) -> ScVal {
77 ScVal::Bool(self)
78 }
79}
80
81impl IntoScVal for String {
83 fn try_into_val(&self) -> Result<ScVal, SorobanHelperError> {
84 let string_m = StringM::<{ u32::MAX }>::try_from(self).map_err(|_| {
85 SorobanHelperError::XdrEncodingFailed("Failed to convert String to StringM".to_string())
86 })?;
87 Ok(ScVal::String(ScString::from(string_m)))
88 }
89
90 fn into_val(self) -> ScVal {
91 let string_m =
92 StringM::<{ u32::MAX }>::try_from(self).expect("Failed to convert String to StringM");
93 ScVal::String(ScString::from(string_m))
94 }
95}
96
97impl IntoScVal for [u8; 32] {
99 fn try_into_val(&self) -> Result<ScVal, SorobanHelperError> {
100 let bytes_m = BytesM::<{ u32::MAX }>::try_from(self).map_err(|_| {
101 SorobanHelperError::XdrEncodingFailed("Failed to convert Bytes to BytesM".to_string())
102 })?;
103 Ok(ScVal::Bytes(ScBytes::from(bytes_m)))
104 }
105
106 fn into_val(self) -> ScVal {
107 let bytes_m =
108 BytesM::<{ u32::MAX }>::try_from(self).expect("Failed to convert Bytes to BytesM");
109 ScVal::Bytes(ScBytes::from(bytes_m))
110 }
111}
112
113impl IntoScVal for Duration {
115 fn try_into_val(&self) -> Result<ScVal, SorobanHelperError> {
116 let milis: u64 = self.as_secs();
117 Ok(ScVal::Duration(XDRDuration::from(milis)))
118 }
119
120 fn into_val(self) -> ScVal {
121 let milis: u64 = self.as_secs();
122 ScVal::Duration(XDRDuration::from(milis))
123 }
124}
125
126impl IntoScVal for Vec<ScVal> {
128 fn try_into_val(&self) -> Result<ScVal, SorobanHelperError> {
129 let vec_m = VecM::try_from(self).map_err(|_| {
130 SorobanHelperError::XdrEncodingFailed("Failed to convert Vec to VecM".to_string())
131 })?;
132 Ok(ScVal::Vec(Some(ScVec::from(vec_m))))
133 }
134
135 fn into_val(self) -> ScVal {
136 let vec_m = VecM::try_from(self).expect("Failed to convert Vec to VecM");
137 ScVal::Vec(Some(ScVec::from(vec_m)))
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144 use stellar_xdr::curr::{PublicKey, Uint256};
145
146 #[test]
147 fn test_account_id_into_scval() {
148 let public_key = PublicKey::PublicKeyTypeEd25519(Uint256([0; 32]));
149 let account_id = AccountId(public_key);
150
151 let scval = account_id.try_into_val().unwrap();
153 match scval {
154 ScVal::Address(ScAddress::Account(id)) => {
155 assert_eq!(id, account_id);
156 }
157 _ => panic!(
158 "Expected ScVal::Address(ScAddress::Account), got {:?}",
159 scval
160 ),
161 }
162
163 let scval = account_id.clone().into_val();
165 match scval {
166 ScVal::Address(ScAddress::Account(id)) => {
167 assert_eq!(id, account_id);
168 }
169 _ => panic!(
170 "Expected ScVal::Address(ScAddress::Account), got {:?}",
171 scval
172 ),
173 }
174 }
175
176 #[test]
177 fn test_u32_into_scval() {
178 let value: u32 = 42;
179
180 let scval = value.try_into_val().unwrap();
182 match scval {
183 ScVal::U32(val) => {
184 assert_eq!(val, value);
185 }
186 _ => panic!("Expected ScVal::U32, got {:?}", scval),
187 }
188
189 let scval = value.into_val();
191 match scval {
192 ScVal::U32(val) => {
193 assert_eq!(val, value);
194 }
195 _ => panic!("Expected ScVal::U32, got {:?}", scval),
196 }
197 }
198
199 #[test]
200 fn test_u64_into_scval() {
201 let value: u64 = 42;
202
203 let scval = value.try_into_val().unwrap();
205 match scval {
206 ScVal::U64(val) => {
207 assert_eq!(val, value);
208 }
209 _ => panic!("Expected ScVal::U64, got {:?}", scval),
210 }
211
212 let scval = value.into_val();
214 match scval {
215 ScVal::U64(val) => {
216 assert_eq!(val, value);
217 }
218 _ => panic!("Expected ScVal::U64, got {:?}", scval),
219 }
220 }
221
222 #[test]
223 fn test_i32_into_scval() {
224 let value: i32 = -42;
225
226 let scval = value.try_into_val().unwrap();
228 match scval {
229 ScVal::I32(val) => {
230 assert_eq!(val, value);
231 }
232 _ => panic!("Expected ScVal::I32, got {:?}", scval),
233 }
234
235 let scval = value.into_val();
237 match scval {
238 ScVal::I32(val) => {
239 assert_eq!(val, value);
240 }
241 _ => panic!("Expected ScVal::I32, got {:?}", scval),
242 }
243 }
244
245 #[test]
246 fn test_i64_into_scval() {
247 let value: i64 = -42;
248
249 let scval = value.try_into_val().unwrap();
251 match scval {
252 ScVal::I64(val) => {
253 assert_eq!(val, value);
254 }
255 _ => panic!("Expected ScVal::I64, got {:?}", scval),
256 }
257
258 let scval = value.into_val();
260 match scval {
261 ScVal::I64(val) => {
262 assert_eq!(val, value);
263 }
264 _ => panic!("Expected ScVal::I64, got {:?}", scval),
265 }
266 }
267
268 #[test]
269 fn test_bool_into_scval() {
270 let value = true;
272
273 let scval = value.try_into_val().unwrap();
274 match scval {
275 ScVal::Bool(val) => {
276 assert_eq!(val, value);
277 }
278 _ => panic!("Expected ScVal::Bool, got {:?}", scval),
279 }
280
281 let scval = value.into_val();
282 match scval {
283 ScVal::Bool(val) => {
284 assert_eq!(val, value);
285 }
286 _ => panic!("Expected ScVal::Bool, got {:?}", scval),
287 }
288
289 let value = false;
291
292 let scval = value.try_into_val().unwrap();
293 match scval {
294 ScVal::Bool(val) => {
295 assert_eq!(val, value);
296 }
297 _ => panic!("Expected ScVal::Bool, got {:?}", scval),
298 }
299 }
300
301 #[test]
302 fn test_string_into_scval() {
303 let value = "test string".to_string();
304
305 let scval = value.try_into_val().unwrap();
307 match scval {
308 ScVal::String(sc_string) => {
309 let string_value: String = sc_string.to_utf8_string_lossy();
310 assert_eq!(string_value, "test string");
311 }
312 _ => panic!("Expected ScVal::String, got {:?}", scval),
313 }
314
315 let value = "test string".to_string();
317 let scval = value.into_val();
318 match scval {
319 ScVal::String(sc_string) => {
320 let string_value: String = sc_string.to_utf8_string_lossy();
321 assert_eq!(string_value, "test string");
322 }
323 _ => panic!("Expected ScVal::String, got {:?}", scval),
324 }
325 }
326
327 #[test]
328 fn test_bytes_into_scval() {
329 let value = [42u8; 32];
330
331 let scval = value.try_into_val().unwrap();
333 match scval {
334 ScVal::Bytes(sc_bytes) => {
335 assert_eq!(sc_bytes.as_slice(), &value);
336 }
337 _ => panic!("Expected ScVal::Bytes, got {:?}", scval),
338 }
339
340 let scval = value.into_val();
342 match scval {
343 ScVal::Bytes(sc_bytes) => {
344 assert_eq!(sc_bytes.as_slice(), &value);
345 }
346 _ => panic!("Expected ScVal::Bytes, got {:?}", scval),
347 }
348 }
349
350 #[test]
351 fn test_duration_into_scval() {
352 let value = Duration::from_secs(42);
353
354 let scval = value.try_into_val().unwrap();
356 match scval {
357 ScVal::Duration(xdr_duration) => {
358 assert_eq!(xdr_duration.0, 42);
359 }
360 _ => panic!("Expected ScVal::Duration, got {:?}", scval),
361 }
362
363 let scval = value.into_val();
365 match scval {
366 ScVal::Duration(xdr_duration) => {
367 assert_eq!(xdr_duration.0, 42);
368 }
369 _ => panic!("Expected ScVal::Duration, got {:?}", scval),
370 }
371 }
372
373 #[test]
374 fn test_vec_scval_into_scval() {
375 let values = vec![ScVal::U32(1), ScVal::I32(-1), ScVal::Bool(true)];
376
377 let scval = values.try_into_val().unwrap();
379 match scval {
380 ScVal::Vec(Some(sc_vec)) => {
381 let vec_values: Vec<ScVal> = sc_vec.0.to_vec();
382 assert_eq!(vec_values.len(), 3);
383 assert_eq!(vec_values[0], ScVal::U32(1));
384 assert_eq!(vec_values[1], ScVal::I32(-1));
385 assert_eq!(vec_values[2], ScVal::Bool(true));
386 }
387 _ => panic!("Expected ScVal::Vec, got {:?}", scval),
388 }
389
390 let values = vec![ScVal::U32(1), ScVal::I32(-1), ScVal::Bool(true)];
392 let scval = values.into_val();
393 match scval {
394 ScVal::Vec(Some(sc_vec)) => {
395 let vec_values: Vec<ScVal> = sc_vec.0.to_vec();
396 assert_eq!(vec_values.len(), 3);
397 assert_eq!(vec_values[0], ScVal::U32(1));
398 assert_eq!(vec_values[1], ScVal::I32(-1));
399 assert_eq!(vec_values[2], ScVal::Bool(true));
400 }
401 _ => panic!("Expected ScVal::Vec, got {:?}", scval),
402 }
403 }
404
405 #[test]
406 fn test_string_conversion_error() {
407 let result = StringM::<{ u32::MAX }>::try_from("test".to_string());
408 assert!(result.is_ok(), "Small string should convert successfully");
409 }
410
411 #[test]
412 fn test_vec_conversion_error() {
413 let small_vec = vec![ScVal::U32(1), ScVal::U32(2)];
414 let result: Result<VecM<ScVal, { u32::MAX }>, _> = VecM::try_from(&small_vec);
415 assert!(result.is_ok(), "Small vector should convert successfully");
416 }
417}