Skip to content

Commit e8732eb

Browse files
Add infallible From conversions for types to ScVal (#1338)
### What Add infallible From conversions for types to ScVal, replacing the existing fallible TryFrom conversions. ### Why When I look through tests I see lots of `try_into().unwrap()` when converting types to their ScVal values. This is unnecessary, we know that the conversions will succeed because the host won't give the SDK types that aren't valid and couldn't be converted. It's just a result of the way the Rust types are setup we can't guarantee the type is always convertible, but in practice they are. Note that this is _not_ really a breaking change, because in the Rust core lib there is a blanket impl for all From conversions to also provide a TryFrom conversion. The only behaviour change is that if there were cases that would fail conversion previously a panic will occur instead of an error when using a TryFrom to do the conversion. In all cases there is no expected failure because the Env guarantees valid host types to be created and we're converting host types to ScVal types. (cherry picked from commit 8fc9f53)
1 parent 68411e7 commit e8732eb

7 files changed

Lines changed: 101 additions & 85 deletions

File tree

soroban-sdk/src/address.rs

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -124,18 +124,21 @@ impl TryFromVal<Env, &Address> for Val {
124124
}
125125

126126
#[cfg(not(target_family = "wasm"))]
127-
impl TryFrom<&Address> for ScVal {
128-
type Error = ConversionError;
129-
fn try_from(v: &Address) -> Result<Self, ConversionError> {
130-
Ok(ScVal::try_from_val(&v.env, &v.obj.to_val())?)
127+
impl From<&Address> for ScVal {
128+
fn from(v: &Address) -> Self {
129+
// This conversion occurs only in test utilities, and theoretically all
130+
// values should convert to an ScVal because the Env won't let the host
131+
// type to exist otherwise, unwrapping. Even if there are edge cases
132+
// that don't, this is a trade off for a better test developer
133+
// experience.
134+
ScVal::try_from_val(&v.env, &v.obj.to_val()).unwrap()
131135
}
132136
}
133137

134138
#[cfg(not(target_family = "wasm"))]
135-
impl TryFrom<Address> for ScVal {
136-
type Error = ConversionError;
137-
fn try_from(v: Address) -> Result<Self, ConversionError> {
138-
(&v).try_into()
139+
impl From<Address> for ScVal {
140+
fn from(v: Address) -> Self {
141+
(&v).into()
139142
}
140143
}
141144

@@ -152,21 +155,19 @@ impl TryFromVal<Env, ScVal> for Address {
152155
}
153156

154157
#[cfg(not(target_family = "wasm"))]
155-
impl TryFrom<&Address> for ScAddress {
156-
type Error = ConversionError;
157-
fn try_from(v: &Address) -> Result<Self, Self::Error> {
158-
match ScVal::try_from_val(&v.env, &v.obj.to_val())? {
159-
ScVal::Address(a) => Ok(a),
160-
_ => Err(ConversionError),
158+
impl From<&Address> for ScAddress {
159+
fn from(v: &Address) -> Self {
160+
match ScVal::try_from_val(&v.env, &v.obj.to_val()).unwrap() {
161+
ScVal::Address(a) => a,
162+
_ => panic!("expected ScVal::Address"),
161163
}
162164
}
163165
}
164166

165167
#[cfg(not(target_family = "wasm"))]
166-
impl TryFrom<Address> for ScAddress {
167-
type Error = ConversionError;
168-
fn try_from(v: Address) -> Result<Self, Self::Error> {
169-
(&v).try_into()
168+
impl From<Address> for ScAddress {
169+
fn from(v: Address) -> Self {
170+
(&v).into()
170171
}
171172
}
172173

soroban-sdk/src/bytes.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -232,18 +232,21 @@ impl From<&Bytes> for Bytes {
232232
}
233233

234234
#[cfg(not(target_family = "wasm"))]
235-
impl TryFrom<&Bytes> for ScVal {
236-
type Error = ConversionError;
237-
fn try_from(v: &Bytes) -> Result<Self, ConversionError> {
238-
Ok(ScVal::try_from_val(&v.env, &v.obj.to_val())?)
235+
impl From<&Bytes> for ScVal {
236+
fn from(v: &Bytes) -> Self {
237+
// This conversion occurs only in test utilities, and theoretically all
238+
// values should convert to an ScVal because the Env won't let the host
239+
// type to exist otherwise, unwrapping. Even if there are edge cases
240+
// that don't, this is a trade off for a better test developer
241+
// experience.
242+
ScVal::try_from_val(&v.env, &v.obj.to_val()).unwrap()
239243
}
240244
}
241245

242246
#[cfg(not(target_family = "wasm"))]
243-
impl TryFrom<Bytes> for ScVal {
244-
type Error = ConversionError;
245-
fn try_from(v: Bytes) -> Result<Self, ConversionError> {
246-
(&v).try_into()
247+
impl From<Bytes> for ScVal {
248+
fn from(v: Bytes) -> Self {
249+
(&v).into()
247250
}
248251
}
249252

soroban-sdk/src/map.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -225,26 +225,29 @@ where
225225
}
226226

227227
#[cfg(not(target_family = "wasm"))]
228-
impl<K, V> TryFrom<&Map<K, V>> for ScVal {
229-
type Error = ConversionError;
230-
fn try_from(v: &Map<K, V>) -> Result<Self, ConversionError> {
231-
Ok(ScVal::try_from_val(&v.env, &v.obj.to_val())?)
228+
impl<K, V> From<&Map<K, V>> for ScVal {
229+
fn from(v: &Map<K, V>) -> Self {
230+
// This conversion occurs only in test utilities, and theoretically all
231+
// values should convert to an ScVal because the Env won't let the host
232+
// type to exist otherwise, unwrapping. Even if there are edge cases
233+
// that don't, this is a trade off for a better test developer
234+
// experience.
235+
ScVal::try_from_val(&v.env, &v.obj.to_val()).unwrap()
232236
}
233237
}
234238

235239
#[cfg(not(target_family = "wasm"))]
236-
impl<K, V> TryFrom<Map<K, V>> for ScVal {
237-
type Error = ConversionError;
238-
fn try_from(v: Map<K, V>) -> Result<Self, ConversionError> {
239-
(&v).try_into()
240+
impl<K, V> From<Map<K, V>> for ScVal {
241+
fn from(v: Map<K, V>) -> Self {
242+
(&v).into()
240243
}
241244
}
242245

243246
#[cfg(not(target_family = "wasm"))]
244247
impl<K, V> TryFromVal<Env, Map<K, V>> for ScVal {
245248
type Error = ConversionError;
246249
fn try_from_val(_e: &Env, v: &Map<K, V>) -> Result<Self, ConversionError> {
247-
v.try_into()
250+
Ok(v.into())
248251
}
249252
}
250253

soroban-sdk/src/num.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -89,22 +89,25 @@ macro_rules! impl_num_wrapping_val_type {
8989
}
9090

9191
#[cfg(not(target_family = "wasm"))]
92-
impl TryFrom<&$wrapper> for ScVal {
93-
type Error = ConversionError;
94-
fn try_from(v: &$wrapper) -> Result<Self, ConversionError> {
92+
impl From<&$wrapper> for ScVal {
93+
fn from(v: &$wrapper) -> Self {
94+
// This conversion occurs only in test utilities, and theoretically all
95+
// values should convert to an ScVal because the Env won't let the host
96+
// type to exist otherwise, unwrapping. Even if there are edge cases
97+
// that don't, this is a trade off for a better test developer
98+
// experience.
9599
if let Ok(ss) = <$small>::try_from(v.val) {
96-
ScVal::try_from(ss)
100+
ScVal::try_from(ss).unwrap()
97101
} else {
98-
Ok(ScVal::try_from_val(&v.env, &v.to_val())?)
102+
ScVal::try_from_val(&v.env, &v.to_val()).unwrap()
99103
}
100104
}
101105
}
102106

103107
#[cfg(not(target_family = "wasm"))]
104-
impl TryFrom<$wrapper> for ScVal {
105-
type Error = ConversionError;
106-
fn try_from(v: $wrapper) -> Result<Self, ConversionError> {
107-
(&v).try_into()
108+
impl From<$wrapper> for ScVal {
109+
fn from(v: $wrapper) -> Self {
110+
(&v).into()
108111
}
109112
}
110113

soroban-sdk/src/string.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -137,18 +137,21 @@ impl From<&String> for String {
137137
}
138138

139139
#[cfg(not(target_family = "wasm"))]
140-
impl TryFrom<&String> for ScVal {
141-
type Error = ConversionError;
142-
fn try_from(v: &String) -> Result<Self, ConversionError> {
143-
Ok(ScVal::try_from_val(&v.env, &v.obj.to_val())?)
140+
impl From<&String> for ScVal {
141+
fn from(v: &String) -> Self {
142+
// This conversion occurs only in test utilities, and theoretically all
143+
// values should convert to an ScVal because the Env won't let the host
144+
// type to exist otherwise, unwrapping. Even if there are edge cases
145+
// that don't, this is a trade off for a better test developer
146+
// experience.
147+
ScVal::try_from_val(&v.env, &v.obj.to_val()).unwrap()
144148
}
145149
}
146150

147151
#[cfg(not(target_family = "wasm"))]
148-
impl TryFrom<String> for ScVal {
149-
type Error = ConversionError;
150-
fn try_from(v: String) -> Result<Self, ConversionError> {
151-
(&v).try_into()
152+
impl From<String> for ScVal {
153+
fn from(v: String) -> Self {
154+
(&v).into()
152155
}
153156
}
154157

soroban-sdk/src/symbol.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -136,31 +136,34 @@ impl TryFromVal<Env, &str> for Symbol {
136136
}
137137

138138
#[cfg(not(target_family = "wasm"))]
139-
impl TryFrom<&Symbol> for ScVal {
140-
type Error = ConversionError;
141-
fn try_from(v: &Symbol) -> Result<Self, ConversionError> {
139+
impl From<&Symbol> for ScVal {
140+
fn from(v: &Symbol) -> Self {
141+
// This conversion occurs only in test utilities, and theoretically all
142+
// values should convert to an ScVal because the Env won't let the host
143+
// type to exist otherwise, unwrapping. Even if there are edge cases
144+
// that don't, this is a trade off for a better test developer
145+
// experience.
142146
if let Ok(ss) = SymbolSmall::try_from(v.val) {
143-
Ok(ScVal::try_from(ss)?)
147+
ScVal::try_from(ss).unwrap()
144148
} else {
145-
let e: Env = v.env.clone().try_into()?;
146-
Ok(ScVal::try_from_val(&e, &v.to_val())?)
149+
let e: Env = v.env.clone().try_into().unwrap();
150+
ScVal::try_from_val(&e, &v.to_val()).unwrap()
147151
}
148152
}
149153
}
150154

151155
#[cfg(not(target_family = "wasm"))]
152-
impl TryFrom<Symbol> for ScVal {
153-
type Error = ConversionError;
154-
fn try_from(v: Symbol) -> Result<Self, ConversionError> {
155-
(&v).try_into()
156+
impl From<Symbol> for ScVal {
157+
fn from(v: Symbol) -> Self {
158+
(&v).into()
156159
}
157160
}
158161

159162
#[cfg(not(target_family = "wasm"))]
160163
impl TryFromVal<Env, Symbol> for ScVal {
161164
type Error = ConversionError;
162165
fn try_from_val(_e: &Env, v: &Symbol) -> Result<Self, ConversionError> {
163-
v.try_into()
166+
Ok(v.into())
164167
}
165168
}
166169

soroban-sdk/src/vec.rs

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -231,46 +231,46 @@ where
231231
use super::xdr::{ScVal, ScVec, VecM};
232232

233233
#[cfg(not(target_family = "wasm"))]
234-
impl<T> TryFrom<&Vec<T>> for ScVal {
235-
type Error = ConversionError;
236-
fn try_from(v: &Vec<T>) -> Result<Self, ConversionError> {
237-
Ok(ScVal::try_from_val(&v.env, &v.obj.to_val())?)
234+
impl<T> From<&Vec<T>> for ScVal {
235+
fn from(v: &Vec<T>) -> Self {
236+
// This conversion occurs only in test utilities, and theoretically all
237+
// values should convert to an ScVal because the Env won't let the host
238+
// type to exist otherwise, unwrapping. Even if there are edge cases
239+
// that don't, this is a trade off for a better test developer
240+
// experience.
241+
ScVal::try_from_val(&v.env, &v.obj.to_val()).unwrap()
238242
}
239243
}
240244

241245
#[cfg(not(target_family = "wasm"))]
242-
impl<T> TryFrom<&Vec<T>> for ScVec {
243-
type Error = ConversionError;
244-
fn try_from(v: &Vec<T>) -> Result<Self, ConversionError> {
245-
if let ScVal::Vec(Some(vec)) = ScVal::try_from(v)? {
246-
Ok(vec)
246+
impl<T> From<&Vec<T>> for ScVec {
247+
fn from(v: &Vec<T>) -> Self {
248+
if let ScVal::Vec(Some(vec)) = ScVal::try_from(v).unwrap() {
249+
vec
247250
} else {
248-
Err(ConversionError)
251+
panic!("expected ScVec")
249252
}
250253
}
251254
}
252255

253256
#[cfg(not(target_family = "wasm"))]
254-
impl<T> TryFrom<Vec<T>> for VecM<ScVal> {
255-
type Error = ConversionError;
256-
fn try_from(v: Vec<T>) -> Result<Self, ConversionError> {
257-
Ok(ScVec::try_from(v)?.0)
257+
impl<T> From<Vec<T>> for VecM<ScVal> {
258+
fn from(v: Vec<T>) -> Self {
259+
ScVec::from(v).0
258260
}
259261
}
260262

261263
#[cfg(not(target_family = "wasm"))]
262-
impl<T> TryFrom<Vec<T>> for ScVal {
263-
type Error = ConversionError;
264-
fn try_from(v: Vec<T>) -> Result<Self, ConversionError> {
265-
(&v).try_into()
264+
impl<T> From<Vec<T>> for ScVal {
265+
fn from(v: Vec<T>) -> Self {
266+
(&v).into()
266267
}
267268
}
268269

269270
#[cfg(not(target_family = "wasm"))]
270-
impl<T> TryFrom<Vec<T>> for ScVec {
271-
type Error = ConversionError;
272-
fn try_from(v: Vec<T>) -> Result<Self, ConversionError> {
273-
(&v).try_into()
271+
impl<T> From<Vec<T>> for ScVec {
272+
fn from(v: Vec<T>) -> Self {
273+
(&v).into()
274274
}
275275
}
276276

0 commit comments

Comments
 (0)