1use crate::xdr::int128_helpers;
2use crate::{
3 num::{i256_from_pieces, i256_into_pieces, u256_from_pieces, u256_into_pieces},
4 DurationSmall, DurationVal, Env, I128Small, I128Val, I256Small, I256Val, I64Small,
5 TimepointSmall, TimepointVal, U128Small, U128Val, U256Small, U256Val, U64Small, U64Val, Val,
6 I256, U256,
7};
8use core::fmt::Debug;
9
10#[cfg(feature = "std")]
11use crate::xdr::{
12 Duration, Int128Parts, Int256Parts, ScVal, TimePoint, UInt128Parts, UInt256Parts,
13};
14#[cfg(feature = "std")]
15use crate::{
16 num, object::ScValObjRef, val::ValConvert, ConversionError, Error, Object, ScValObject,
17 SymbolSmall, Tag,
18};
19
20pub trait Convert<F, T> {
23 type Error: Debug + Into<crate::Error>;
24 fn convert(&self, f: F) -> Result<T, Self::Error>;
25}
26
27pub trait TryIntoVal<E: Env, V> {
32 type Error: Debug + Into<crate::Error>;
33 fn try_into_val(&self, env: &E) -> Result<V, Self::Error>;
34}
35
36pub trait TryFromVal<E: Env, V: ?Sized>: Sized {
43 type Error: Debug + Into<crate::Error>;
44 fn try_from_val(env: &E, v: &V) -> Result<Self, Self::Error>;
45}
46
47impl<E: Env, T, U> TryIntoVal<E, T> for U
50where
51 T: TryFromVal<E, U>,
52{
53 type Error = T::Error;
54
55 fn try_into_val(&self, env: &E) -> Result<T, Self::Error> {
56 T::try_from_val(env, self)
57 }
58}
59
60impl<E: Env> TryFromVal<E, Val> for i64 {
63 type Error = crate::Error;
64
65 fn try_from_val(env: &E, val: &Val) -> Result<Self, Self::Error> {
66 let val = *val;
67 if let Ok(so) = I64Small::try_from(val) {
68 Ok(so.into())
69 } else {
70 let obj = val.try_into()?;
71 Ok(env.obj_to_i64(obj).map_err(Into::into)?)
72 }
73 }
74}
75
76impl<E: Env> TryFromVal<E, i64> for Val {
77 type Error = crate::Error;
78
79 fn try_from_val(env: &E, v: &i64) -> Result<Self, Self::Error> {
80 let v = *v;
81 if let Ok(so) = I64Small::try_from(v) {
82 Ok(so.into())
83 } else {
84 Ok(env.obj_from_i64(v).map_err(Into::into)?.to_val())
85 }
86 }
87}
88
89impl<E: Env> TryFromVal<E, &i64> for Val {
90 type Error = crate::Error;
91
92 fn try_from_val(env: &E, v: &&i64) -> Result<Self, Self::Error> {
93 Self::try_from_val(env, *v)
94 }
95}
96
97impl<E: Env> TryFromVal<E, Val> for u64 {
100 type Error = crate::Error;
101
102 fn try_from_val(env: &E, val: &Val) -> Result<Self, Self::Error> {
103 let val = *val;
104 if let Ok(so) = U64Small::try_from(val) {
105 Ok(so.into())
106 } else {
107 let obj = val.try_into()?;
108 Ok(env.obj_to_u64(obj).map_err(Into::into)?)
109 }
110 }
111}
112
113impl<E: Env> TryFromVal<E, u64> for Val {
114 type Error = crate::Error;
115
116 fn try_from_val(env: &E, v: &u64) -> Result<Self, Self::Error> {
117 Ok(U64Val::try_from_val(env, v)?.to_val())
118 }
119}
120
121impl<E: Env> TryFromVal<E, &u64> for Val {
122 type Error = crate::Error;
123
124 fn try_from_val(env: &E, v: &&u64) -> Result<Self, Self::Error> {
125 Self::try_from_val(env, *v)
126 }
127}
128
129impl<E: Env> TryFromVal<E, U64Val> for u64 {
130 type Error = crate::Error;
131
132 fn try_from_val(env: &E, val: &U64Val) -> Result<Self, Self::Error> {
133 let val = *val;
134 if let Ok(so) = U64Small::try_from(val) {
135 Ok(so.into())
136 } else {
137 let obj = val.try_into()?;
138 Ok(env.obj_to_u64(obj).map_err(Into::into)?)
139 }
140 }
141}
142
143impl<E: Env> TryFromVal<E, u64> for U64Val {
144 type Error = crate::Error;
145
146 fn try_from_val(env: &E, v: &u64) -> Result<Self, Self::Error> {
147 let v = *v;
148 if let Ok(so) = U64Small::try_from(v) {
149 Ok(so.into())
150 } else {
151 Ok(env.obj_from_u64(v).map_err(Into::into)?.into())
152 }
153 }
154}
155
156impl<E: Env> TryFromVal<E, TimepointVal> for u64 {
159 type Error = crate::Error;
160
161 fn try_from_val(env: &E, val: &TimepointVal) -> Result<Self, Self::Error> {
162 let val = *val;
163 if let Ok(so) = TimepointSmall::try_from(val) {
164 Ok(so.into())
165 } else {
166 let obj = val.try_into()?;
167 Ok(env.timepoint_obj_to_u64(obj).map_err(Into::into)?)
168 }
169 }
170}
171
172impl<E: Env> TryFromVal<E, u64> for TimepointVal {
173 type Error = crate::Error;
174
175 fn try_from_val(env: &E, v: &u64) -> Result<Self, Self::Error> {
176 let v = *v;
177 if let Ok(so) = TimepointSmall::try_from(v) {
178 Ok(so.into())
179 } else {
180 Ok(env.timepoint_obj_from_u64(v).map_err(Into::into)?.into())
181 }
182 }
183}
184
185impl<E: Env> TryFromVal<E, DurationVal> for u64 {
186 type Error = crate::Error;
187
188 fn try_from_val(env: &E, val: &DurationVal) -> Result<Self, Self::Error> {
189 let val = *val;
190 if let Ok(so) = DurationSmall::try_from(val) {
191 Ok(so.into())
192 } else {
193 let obj = val.try_into()?;
194 Ok(env.duration_obj_to_u64(obj).map_err(Into::into)?)
195 }
196 }
197}
198
199impl<E: Env> TryFromVal<E, u64> for DurationVal {
200 type Error = crate::Error;
201
202 fn try_from_val(env: &E, v: &u64) -> Result<Self, Self::Error> {
203 let v = *v;
204 if let Ok(so) = DurationSmall::try_from(v) {
205 Ok(so.into())
206 } else {
207 Ok(env.duration_obj_from_u64(v).map_err(Into::into)?.into())
208 }
209 }
210}
211
212impl<E: Env> TryFromVal<E, Val> for i128 {
215 type Error = crate::Error;
216
217 fn try_from_val(env: &E, v: &Val) -> Result<Self, Self::Error> {
218 let v = *v;
219 if let Ok(so) = I128Small::try_from(v) {
220 Ok(so.into())
221 } else {
222 let obj = v.try_into()?;
223 let hi = env.obj_to_i128_hi64(obj).map_err(Into::into)?;
224 let lo = env.obj_to_i128_lo64(obj).map_err(Into::into)?;
225 Ok(int128_helpers::i128_from_pieces(hi, lo))
226 }
227 }
228}
229
230impl<E: Env> TryFromVal<E, i128> for Val {
231 type Error = crate::Error;
232
233 fn try_from_val(env: &E, v: &i128) -> Result<Self, Self::Error> {
234 Ok(I128Val::try_from_val(env, v)?.to_val())
235 }
236}
237
238impl<E: Env> TryFromVal<E, &i128> for Val {
239 type Error = crate::Error;
240
241 fn try_from_val(env: &E, v: &&i128) -> Result<Self, Self::Error> {
242 Self::try_from_val(env, *v)
243 }
244}
245
246impl<E: Env> TryFromVal<E, i128> for I128Val {
247 type Error = crate::Error;
248
249 fn try_from_val(env: &E, v: &i128) -> Result<Self, Self::Error> {
250 let v = *v;
251 if let Ok(so) = I128Small::try_from(v) {
252 Ok(so.into())
253 } else {
254 Ok(env
255 .obj_from_i128_pieces(int128_helpers::i128_hi(v), int128_helpers::i128_lo(v))
256 .map_err(Into::into)?
257 .into())
258 }
259 }
260}
261
262impl<E: Env> TryFromVal<E, Val> for u128 {
265 type Error = crate::Error;
266
267 fn try_from_val(env: &E, v: &Val) -> Result<Self, Self::Error> {
268 let v = *v;
269 if let Ok(so) = U128Small::try_from(v) {
270 Ok(so.into())
271 } else {
272 let obj = v.try_into()?;
273 let hi = env.obj_to_u128_hi64(obj).map_err(Into::into)?;
274 let lo = env.obj_to_u128_lo64(obj).map_err(Into::into)?;
275 Ok(int128_helpers::u128_from_pieces(hi, lo))
276 }
277 }
278}
279
280impl<E: Env> TryFromVal<E, u128> for Val {
281 type Error = crate::Error;
282
283 fn try_from_val(env: &E, v: &u128) -> Result<Self, Self::Error> {
284 Ok(U128Val::try_from_val(env, v)?.to_val())
285 }
286}
287
288impl<E: Env> TryFromVal<E, &u128> for Val {
289 type Error = crate::Error;
290
291 fn try_from_val(env: &E, v: &&u128) -> Result<Self, Self::Error> {
292 Self::try_from_val(env, *v)
293 }
294}
295
296impl<E: Env> TryFromVal<E, u128> for U128Val {
297 type Error = crate::Error;
298
299 fn try_from_val(env: &E, v: &u128) -> Result<Self, Self::Error> {
300 let v = *v;
301 if let Ok(so) = U128Small::try_from(v) {
302 Ok(so.into())
303 } else {
304 Ok(env
305 .obj_from_u128_pieces(int128_helpers::u128_hi(v), int128_helpers::u128_lo(v))
306 .map_err(Into::into)?
307 .into())
308 }
309 }
310}
311
312impl<E: Env> TryFromVal<E, Val> for I256 {
314 type Error = crate::Error;
315
316 fn try_from_val(env: &E, v: &Val) -> Result<Self, Self::Error> {
317 let v = *v;
318 if let Ok(so) = I256Small::try_from(v) {
319 Ok(so.into())
320 } else {
321 let obj = v.try_into()?;
322 let hi_hi = env.obj_to_i256_hi_hi(obj).map_err(Into::into)?;
323 let hi_lo = env.obj_to_i256_hi_lo(obj).map_err(Into::into)?;
324 let lo_hi = env.obj_to_i256_lo_hi(obj).map_err(Into::into)?;
325 let lo_lo = env.obj_to_i256_lo_lo(obj).map_err(Into::into)?;
326 Ok(i256_from_pieces(hi_hi, hi_lo, lo_hi, lo_lo))
327 }
328 }
329}
330
331impl<E: Env> TryFromVal<E, I256> for Val {
332 type Error = crate::Error;
333
334 fn try_from_val(env: &E, v: &I256) -> Result<Self, Self::Error> {
335 Ok(I256Val::try_from_val(env, v)?.to_val())
336 }
337}
338
339impl<E: Env> TryFromVal<E, &I256> for Val {
340 type Error = crate::Error;
341
342 fn try_from_val(env: &E, v: &&I256) -> Result<Self, Self::Error> {
343 Self::try_from_val(env, *v)
344 }
345}
346
347impl<E: Env> TryFromVal<E, I256> for I256Val {
348 type Error = crate::Error;
349
350 fn try_from_val(env: &E, v: &I256) -> Result<Self, Self::Error> {
351 let v = *v;
352 if let Ok(so) = I256Small::try_from(v) {
353 Ok(so.into())
354 } else {
355 let (hi_hi, hi_lo, lo_hi, lo_lo) = i256_into_pieces(v);
356 Ok(env
357 .obj_from_i256_pieces(hi_hi, hi_lo, lo_hi, lo_lo)
358 .map_err(Into::into)?
359 .into())
360 }
361 }
362}
363
364impl<E: Env> TryFromVal<E, Val> for U256 {
366 type Error = crate::Error;
367
368 fn try_from_val(env: &E, v: &Val) -> Result<Self, Self::Error> {
369 let v = *v;
370 if let Ok(so) = U256Small::try_from(v) {
371 Ok(so.into())
372 } else {
373 let obj = v.try_into()?;
374 let hi_hi = env.obj_to_u256_hi_hi(obj).map_err(Into::into)?;
375 let hi_lo = env.obj_to_u256_hi_lo(obj).map_err(Into::into)?;
376 let lo_hi = env.obj_to_u256_lo_hi(obj).map_err(Into::into)?;
377 let lo_lo = env.obj_to_u256_lo_lo(obj).map_err(Into::into)?;
378 Ok(u256_from_pieces(hi_hi, hi_lo, lo_hi, lo_lo))
379 }
380 }
381}
382
383impl<E: Env> TryFromVal<E, U256> for Val {
384 type Error = crate::Error;
385
386 fn try_from_val(env: &E, v: &U256) -> Result<Self, Self::Error> {
387 Ok(U256Val::try_from_val(env, v)?.to_val())
388 }
389}
390
391impl<E: Env> TryFromVal<E, &U256> for Val {
392 type Error = crate::Error;
393
394 fn try_from_val(env: &E, v: &&U256) -> Result<Self, Self::Error> {
395 Self::try_from_val(env, *v)
396 }
397}
398
399impl<E: Env> TryFromVal<E, U256> for U256Val {
400 type Error = crate::Error;
401
402 fn try_from_val(env: &E, v: &U256) -> Result<Self, Self::Error> {
403 let v = *v;
404 if let Ok(so) = U256Small::try_from(v) {
405 Ok(so.into())
406 } else {
407 let (hi_hi, hi_lo, lo_hi, lo_lo) = u256_into_pieces(v);
408 Ok(env
409 .obj_from_u256_pieces(hi_hi, hi_lo, lo_hi, lo_lo)
410 .map_err(Into::into)?
411 .into())
412 }
413 }
414}
415
416#[cfg(feature = "std")]
419impl<E: Env> TryFromVal<E, Val> for ScVal
420where
421 ScValObject: TryFromVal<E, Object>,
422 <ScValObject as TryFromVal<E, Object>>::Error: Into<crate::Error>,
423{
424 type Error = crate::Error;
425
426 fn try_from_val(env: &E, val: &Val) -> Result<Self, crate::Error> {
427 if let Ok(object) = Object::try_from(val) {
428 let scvo: ScValObject = object.try_into_val(env).map_err(|e| {
429 let e: <ScValObject as TryFromVal<E, Object>>::Error = e;
430 let e: crate::Error = e.into();
431 e
432 })?;
433 return Ok(scvo.into());
434 }
435 let val = *val;
436 match val.get_tag() {
437 Tag::False => Ok(ScVal::Bool(false)),
438 Tag::True => Ok(ScVal::Bool(true)),
439 Tag::Void => Ok(ScVal::Void),
440 Tag::Error => {
441 let error: Error = unsafe { <Error as ValConvert>::unchecked_from_val(val) };
442 Ok(error.try_into()?)
443 }
444 Tag::U32Val => Ok(ScVal::U32(val.get_major())),
445 Tag::I32Val => Ok(ScVal::I32(val.get_major() as i32)),
446 Tag::U64Small => Ok(ScVal::U64(val.get_body())),
447 Tag::I64Small => Ok(ScVal::I64(val.get_signed_body())),
448 Tag::TimepointSmall => Ok(ScVal::Timepoint(TimePoint(val.get_body()))),
449 Tag::DurationSmall => Ok(ScVal::Duration(Duration(val.get_body()))),
450 Tag::U128Small => Ok(ScVal::U128(UInt128Parts {
451 hi: 0,
452 lo: val.get_body(),
453 })),
454 Tag::I128Small => {
455 let body = val.get_signed_body() as i128;
456 Ok(ScVal::I128(Int128Parts {
457 hi: (body >> 64) as i64,
458 lo: body as u64,
459 }))
460 }
461 Tag::U256Small => Ok(ScVal::U256(UInt256Parts {
462 hi_hi: 0,
463 hi_lo: 0,
464 lo_hi: 0,
465 lo_lo: val.get_body(),
466 })),
467 Tag::I256Small => {
468 let body = val.get_signed_body() as i128;
469 let (hi_hi, hi_lo, lo_hi, lo_lo) = i256_into_pieces(I256::from(body));
470 Ok(ScVal::I256(Int256Parts {
471 hi_hi,
472 hi_lo,
473 lo_hi,
474 lo_lo,
475 }))
476 }
477 Tag::SymbolSmall => {
478 let sym: SymbolSmall =
479 unsafe { <SymbolSmall as ValConvert>::unchecked_from_val(val) };
480 let str: String = sym.into_iter().collect();
481 Ok(ScVal::Symbol(crate::xdr::ScSymbol(
482 str.as_bytes().try_into()?,
483 )))
484 }
485
486 Tag::U64Object
489 | Tag::I64Object
490 | Tag::TimepointObject
491 | Tag::DurationObject
492 | Tag::U128Object
493 | Tag::I128Object
494 | Tag::U256Object
495 | Tag::I256Object
496 | Tag::BytesObject
497 | Tag::StringObject
498 | Tag::SymbolObject
499 | Tag::VecObject
500 | Tag::MapObject
501 | Tag::AddressObject
502 | Tag::SmallCodeUpperBound
503 | Tag::ObjectCodeLowerBound
504 | Tag::ObjectCodeUpperBound
505 | Tag::Bad => Err(ConversionError.into()),
506 }
507 }
508}
509
510#[cfg(feature = "std")]
511fn require_or_conversion_error(b: bool) -> Result<(), ConversionError> {
512 if !b {
513 Err(ConversionError)
514 } else {
515 Ok(())
516 }
517}
518
519#[cfg(feature = "std")]
520impl<E: Env> TryFromVal<E, ScVal> for Val
521where
522 Object: for<'a> TryFromVal<E, ScValObjRef<'a>>,
523 for<'a> <Object as TryFromVal<E, ScValObjRef<'a>>>::Error: Into<crate::Error>,
524{
525 type Error = crate::Error;
526 fn try_from_val(env: &E, val: &ScVal) -> Result<Val, Self::Error> {
527 if !Val::can_represent_scval(val) {
528 return Err(ConversionError.into());
529 }
530
531 if let Some(scvo) = ScValObjRef::classify(val) {
532 let obj = Object::try_from_val(env, &scvo).map_err(|e| {
533 let e: <Object as TryFromVal<E, ScValObjRef>>::Error = e;
534 let e: crate::Error = e.into();
535 e
536 })?;
537 return Ok(obj.into());
538 }
539
540 Ok(match val {
542 ScVal::Bool(b) => Val::from_bool(*b).into(),
543 ScVal::Void => Val::from_void().into(),
544 ScVal::Error(e) => e.into(),
545 ScVal::U32(u) => (*u).into(),
546 ScVal::I32(i) => (*i).into(),
547 ScVal::U64(u) => {
548 require_or_conversion_error(num::is_small_u64(*u))?;
549 unsafe { Val::from_body_and_tag(*u, Tag::U64Small) }
550 }
551 ScVal::I64(i) => {
552 require_or_conversion_error(num::is_small_i64(*i))?;
553 unsafe { Val::from_body_and_tag(*i as u64, Tag::I64Small) }
554 }
555 ScVal::Timepoint(TimePoint(u)) => {
556 require_or_conversion_error(num::is_small_u64(*u))?;
557 unsafe { Val::from_body_and_tag(*u, Tag::TimepointSmall) }
558 }
559 ScVal::Duration(Duration(u)) => {
560 require_or_conversion_error(num::is_small_u64(*u))?;
561 unsafe { Val::from_body_and_tag(*u, Tag::DurationSmall) }
562 }
563 ScVal::U128(u) => {
564 let u: u128 = u.into();
565 require_or_conversion_error(num::is_small_u128(u))?;
566 unsafe { Val::from_body_and_tag(u as u64, Tag::U128Small) }
567 }
568 ScVal::I128(i) => {
569 let i: i128 = i.into();
570 require_or_conversion_error(num::is_small_i128(i))?;
571 unsafe { Val::from_body_and_tag((i as i64) as u64, Tag::I128Small) }
572 }
573 ScVal::U256(u) => {
574 require_or_conversion_error(num::is_small_u256_parts(u))?;
575 unsafe { Val::from_body_and_tag(u.lo_lo, Tag::U256Small) }
576 }
577 ScVal::I256(i) => {
578 require_or_conversion_error(num::is_small_i256_parts(i))?;
579 unsafe { Val::from_body_and_tag(i.lo_lo, Tag::I256Small) }
580 }
581 ScVal::Symbol(bytes) => {
582 SymbolSmall::try_from_bytes(bytes.as_slice())?.into()
585 }
586
587 ScVal::Bytes(_)
591 | ScVal::String(_)
592 | ScVal::Vec(_)
593 | ScVal::Map(_)
594 | ScVal::Address(_)
595 | ScVal::LedgerKeyNonce(_)
596 | ScVal::LedgerKeyContractInstance
597 | ScVal::ContractInstance(_) => return Err(ConversionError.into()),
598 })
599 }
600}
601
602#[cfg(feature = "std")]
603impl<E: Env> TryFromVal<E, &ScVal> for Val
604where
605 Object: for<'a> TryFromVal<E, ScValObjRef<'a>>,
606 for<'a> <Object as TryFromVal<E, ScValObjRef<'a>>>::Error: Into<crate::Error>,
607{
608 type Error = crate::Error;
609 fn try_from_val(env: &E, val: &&ScVal) -> Result<Val, Self::Error> {
610 Self::try_from_val(env, *val)
611 }
612}