soroban_env_common/
object.rs1use crate::xdr::{Duration, ScVal, TimePoint};
2use crate::{
3 impl_val_wrapper_base, num, val::ValConvert, Compare, Convert, Env, Tag, TryFromVal, Val,
4};
5use core::{cmp::Ordering, fmt::Debug};
6
7#[repr(transparent)]
11#[derive(Copy, Clone)]
12pub struct Object(pub(crate) Val);
13impl_val_wrapper_base!(Object);
14
15impl ValConvert for Object {
16 fn is_val_type(v: Val) -> bool {
17 v.is_object()
18 }
19
20 unsafe fn unchecked_from_val(v: Val) -> Self {
21 Object(v)
22 }
23}
24
25impl Object {
26 #[inline(always)]
27 pub const fn get_handle(&self) -> u32 {
28 self.as_val().get_major()
29 }
30
31 #[inline(always)]
32 pub const fn from_handle_and_tag(handle: u32, tag: Tag) -> Self {
33 debug_assert!(tag.is_object());
34 unsafe { Object(Val::from_major_minor_and_tag(handle, 0, tag)) }
35 }
36}
37
38impl<E: Env> Compare<Object> for E {
39 type Error = E::Error;
40
41 fn compare(&self, a: &Object, b: &Object) -> Result<Ordering, Self::Error> {
42 self.compare(&a.to_val(), &b.to_val())
43 }
44}
45
46#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
54pub struct ScValObject(ScVal);
55impl From<ScValObject> for ScVal {
56 fn from(value: ScValObject) -> Self {
57 value.0
58 }
59}
60
61impl<E> TryFromVal<E, Object> for ScValObject
62where
63 E: Env + Convert<Object, ScValObject>,
64{
65 type Error = <E as Convert<Object, ScValObject>>::Error;
66 fn try_from_val(env: &E, val: &Object) -> Result<Self, Self::Error> {
67 env.convert(*val)
68 }
69}
70
71impl<'a, E> TryFromVal<E, ScValObjRef<'a>> for Object
72where
73 E: Env + Convert<ScValObjRef<'a>, Object>,
74{
75 type Error = crate::Error;
76
77 fn try_from_val(env: &E, v: &ScValObjRef<'a>) -> Result<Self, Self::Error> {
78 match env.convert(*v) {
79 Ok(obj) => Ok(obj),
80 Err(e) => Err(e.into()),
81 }
82 }
83}
84
85impl ScValObject {
86 pub fn classify(value: ScVal) -> Result<ScValObject, ScVal> {
89 if ScValObjRef::classify(&value).is_some() {
90 Ok(ScValObject(value))
91 } else {
92 Err(value)
93 }
94 }
95
96 pub unsafe fn unchecked_from_val(value: ScVal) -> ScValObject {
99 ScValObject(value)
100 }
101}
102
103impl AsRef<ScVal> for ScValObject {
104 fn as_ref(&self) -> &ScVal {
105 &self.0
106 }
107}
108
109#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
110pub struct ScValObjRef<'a>(&'a ScVal);
111
112impl<'a> From<ScValObjRef<'a>> for &'a ScVal {
113 fn from(val: ScValObjRef<'a>) -> Self {
114 val.0
115 }
116}
117
118impl AsRef<ScVal> for ScValObjRef<'_> {
119 fn as_ref(&self) -> &ScVal {
120 self.0
121 }
122}
123
124impl<'a> ScValObjRef<'a> {
125 pub fn classify(value: &'a ScVal) -> Option<Self> {
128 match value {
129 ScVal::Bool(_)
132 | ScVal::Void
133 | ScVal::Error(_)
134 | ScVal::U32(_)
135 | ScVal::I32(_)
136 | ScVal::LedgerKeyContractInstance
137 | ScVal::LedgerKeyNonce(_)
138 | ScVal::ContractInstance(_) => None,
139
140 ScVal::Bytes(_)
142 | ScVal::String(_)
143 | ScVal::Vec(_)
144 | ScVal::Map(_)
145 | ScVal::Address(_) => Some(ScValObjRef(value)),
146
147 ScVal::U64(u) | ScVal::Timepoint(TimePoint(u)) | ScVal::Duration(Duration(u)) => {
150 if num::is_small_u64(*u) {
151 None
152 } else {
153 Some(ScValObjRef(value))
154 }
155 }
156 ScVal::I64(i) => {
157 if num::is_small_i64(*i) {
158 None
159 } else {
160 Some(ScValObjRef(value))
161 }
162 }
163 ScVal::U128(u) => {
164 if num::is_small_u128(u.into()) {
165 None
166 } else {
167 Some(ScValObjRef(value))
168 }
169 }
170 ScVal::I128(i) => {
171 if num::is_small_i128(i.into()) {
172 None
173 } else {
174 Some(ScValObjRef(value))
175 }
176 }
177 ScVal::U256(u) => {
178 if num::is_small_u256_parts(u) {
179 None
180 } else {
181 Some(ScValObjRef(value))
182 }
183 }
184 ScVal::I256(i) => {
185 if num::is_small_i256_parts(i) {
186 None
187 } else {
188 Some(ScValObjRef(value))
189 }
190 }
191 ScVal::Symbol(s) => {
192 if s.len() <= crate::symbol::MAX_SMALL_CHARS {
193 None
194 } else {
195 Some(ScValObjRef(value))
196 }
197 }
198 }
199 }
200}