Repository: stellar/rs-soroban-env
Pull request #357 (2022-08-22 17:15:26)

Replace TryFrom<EnvVal<>> with TryFromVal<>
### What

Replace TryFrom<EnvVal<>> with TryFromVal<>, and disconnect the link between TryFrom and TryFromVal.

### Why

Disconnecting TryFrom and TryFromVal is necessary because we otherwise can't provide an implementation for all Option<T> for conversion in. This is because the core lib has an impl of T to Option<T> for all T.

TryFromVal is more of a serialization interface than it is a type conversion interface, even though we present it as the latter. Given that our interface has unique and specific behavior for all types, even builtin types like Option<T>, I think we need to have it standalone and not utilize the builtin From/TryFrom traits.

There is an alternative, we could manually or with macros implement every Option<T> interface we need, but it feels like philosophically we shouldn't be saying TryFromVal should always be bound to TryFrom. And after making this change I gotta say it simplifies things to take away some of these blanket implementations which is really all this change is doing.

### Known limitations

[TODO or N/A]


leighmcculloch: This PR is ready, but I'm making the same changes to the SDK so I can land both at the same time and validate that this is actually an okay change from the SDKs POV.

Patch:
diff --git a/soroban-env-common/src/array.rs b/soroban-env-common/src/array.rs
index f7801114..621dd948 100644
--- a/soroban-env-common/src/array.rs
+++ b/soroban-env-common/src/array.rs
@@ -1,16 +1,19 @@
 use stellar_xdr::ScObjectType;
 
-use crate::{ConversionError, Env, EnvVal, IntoVal, Object, RawVal, RawValConvertible, TryIntoVal};
+use crate::{
+    ConversionError, Env, EnvVal, IntoVal, Object, RawVal, RawValConvertible, TryFromVal,
+    TryIntoVal,
+};
 
-impl<E: Env, const N: usize> TryFrom<EnvVal<E, RawVal>> for [u8; N] {
+impl<E: Env, const N: usize> TryFromVal<E, RawVal> for [u8; N] {
     type Error = ConversionError;
 
-    fn try_from(ev: EnvVal<E, RawVal>) -> Result<Self, Self::Error> {
-        if !Object::val_is_obj_type(ev.val, ScObjectType::Bytes) {
+    fn try_from_val(env: &E, val: RawVal) -> Result<Self, Self::Error> {
+        if !Object::val_is_obj_type(val, ScObjectType::Bytes) {
             return Err(ConversionError);
         }
-        let env = ev.env.clone();
-        let bin = unsafe { Object::unchecked_from_val(ev.val) };
+        let env = env.clone();
+        let bin = unsafe { Object::unchecked_from_val(val) };
         let len = unsafe { u32::unchecked_from_val(env.binary_len(bin)) };
         if len as usize != N {
             return Err(ConversionError);
@@ -22,14 +25,10 @@ impl<E: Env, const N: usize> TryFrom<EnvVal<E, RawVal>> for [u8; N] {
 }
 
 impl<E: Env, const N: usize> TryIntoVal<E, [u8; N]> for RawVal {
-    type Error = ConversionError;
+    type Error = <[u8; N] as TryFromVal<E, RawVal>>::Error;
     #[inline(always)]
     fn try_into_val(self, env: &E) -> Result<[u8; N], Self::Error> {
-        EnvVal {
-            env: env.clone(),
-            val: self,
-        }
-        .try_into()
+        <_ as TryFromVal<_, _>>::try_from_val(env, self)
     }
 }
 
diff --git a/soroban-env-common/src/env_val.rs b/soroban-env-common/src/env_val.rs
index bb0fe751..dcb236dd 100644
--- a/soroban-env-common/src/env_val.rs
+++ b/soroban-env-common/src/env_val.rs
@@ -11,7 +11,7 @@ use super::{
     raw_val::{RawVal, RawValConvertible},
     Env,
 };
-use core::{cmp::Ordering, fmt::Debug};
+use core::{cmp::Ordering, convert::Infallible, fmt::Debug};
 
 /// Some type of value coupled to a specific instance of [Env], which some of
 /// the value's methods may call into to support some conversion and comparison
@@ -83,15 +83,6 @@ pub trait IntoVal<E: Env, V>: Sized {
     }
 }
 
-impl<E: Env, F, T> IntoVal<E, T> for F
-where
-    F: Into<T>,
-{
-    fn into_val(self, _: &E) -> T {
-        self.into()
-    }
-}
-
 pub trait TryIntoVal<E: Env, V>: Sized {
     type Error;
     fn try_into_val(self, env: &E) -> Result<V, Self::Error>;
@@ -104,62 +95,52 @@ pub trait TryIntoVal<E: Env, V>: Sized {
     }
 }
 
-impl<E: Env, F, T> TryIntoVal<E, T> for F
-where
-    F: TryInto<T>,
-{
-    type Error = F::Error;
-
-    fn try_into_val(self, _: &E) -> Result<T, Self::Error> {
-        self.try_into()
-    }
-}
-
 pub trait TryFromVal<E: Env, V>: Sized {
     type Error;
     fn try_from_val(env: &E, v: V) -> Result<Self, Self::Error>;
 }
 
-impl<E: Env, V, T> TryFromVal<E, V> for T
-where
-    T: TryFrom<EnvVal<E, V>>,
-{
-    type Error = T::Error;
-    fn try_from_val(env: &E, v: V) -> Result<Self, Self::Error> {
-        Self::try_from(EnvVal {
-            env: env.clone(),
-            val: v,
-        })
-    }
-}
-
 impl<E: Env> From<EnvVal<E, RawVal>> for RawVal {
     fn from(ev: EnvVal<E, RawVal>) -> Self {
         ev.val
     }
 }
 
-impl<E: Env> EnvVal<E, RawVal> {
-    pub(crate) fn log_err_convert<T>(self) {
-        self.env().log_static_fmt_val_static_str(
-            "can't convert {} to {}",
-            self.to_raw(),
-            core::any::type_name::<T>(),
-        );
+impl<E: Env, V> IntoVal<E, V> for EnvVal<E, V> {
+    fn into_val(self, _env: &E) -> V {
+        self.val
     }
 }
 
-impl<E: Env> TryFrom<EnvVal<E, RawVal>> for i64 {
+impl<E: Env, V> TryFromVal<E, V> for EnvVal<E, V> {
+    type Error = Infallible;
+    fn try_from_val(env: &E, val: V) -> Result<Self, Self::Error> {
+        Ok(EnvVal {
+            env: env.clone(),
+            val,
+        })
+    }
+}
+
+pub(crate) fn log_err_convert<T>(env: &impl Env, val: &impl AsRef<RawVal>) {
+    env.log_static_fmt_val_static_str(
+        "can't convert {} to {}",
+        *val.as_ref(),
+        core::any::type_name::<T>(),
+    );
+}
+
+impl<E: Env> TryFromVal<E, RawVal> for i64 {
     type Error = ConversionError;
 
-    fn try_from(ev: EnvVal<E, RawVal>) -> Result<Self, Self::Error> {
-        if ev.val.is_u63() {
-            Ok(unsafe { ev.val.unchecked_as_u63() })
-        } else if Object::val_is_obj_type(ev.val, ScObjectType::I64) {
-            let obj = unsafe { Object::unchecked_from_val(ev.val) };
-            Ok(ev.env.obj_to_i64(obj))
+    fn try_from_val(env: &E, val: RawVal) -> Result<Self, Self::Error> {
+        if val.is_u63() {
+            Ok(unsafe { val.unchecked_as_u63() })
+        } else if Object::val_is_obj_type(val, ScObjectType::I64) {
+            let obj = unsafe { Object::unchecked_from_val(val) };
+            Ok(env.obj_to_i64(obj))
         } else {
-            ev.log_err_convert::<i64>();
+            log_err_convert::<i64>(env, &val);
             Err(ConversionError)
         }
     }
@@ -183,24 +164,21 @@ impl<E: Env> TryIntoVal<E, RawVal> for i64 {
 }
 
 impl<E: Env> TryIntoVal<E, i64> for RawVal {
-    type Error = ConversionError;
+    type Error = <i64 as TryFromVal<E, RawVal>>::Error;
     fn try_into_val(self, env: &E) -> Result<i64, Self::Error> {
-        TryFrom::try_from(EnvVal {
-            env: env.clone(),
-            val: self,
-        })
+        <_ as TryFromVal<_, _>>::try_from_val(env, self)
     }
 }
 
-impl<E: Env> TryFrom<EnvVal<E, RawVal>> for u64 {
+impl<E: Env> TryFromVal<E, RawVal> for u64 {
     type Error = ConversionError;
 
-    fn try_from(ev: EnvVal<E, RawVal>) -> Result<Self, Self::Error> {
-        if Object::val_is_obj_type(ev.val, ScObjectType::U64) {
-            let obj = unsafe { Object::unchecked_from_val(ev.val) };
-            Ok(ev.env.obj_to_u64(obj))
+    fn try_from_val(env: &E, val: RawVal) -> Result<Self, Self::Error> {
+        if Object::val_is_obj_type(val, ScObjectType::U64) {
+            let obj = unsafe { Object::unchecked_from_val(val) };
+            Ok(env.obj_to_u64(obj))
         } else {
-            ev.log_err_convert::<u64>();
+            log_err_convert::<u64>(env, &val);
             Err(ConversionError)
         }
     }
@@ -220,26 +198,20 @@ impl<E: Env> TryIntoVal<E, RawVal> for u64 {
 }
 
 impl<E: Env> TryIntoVal<E, u64> for RawVal {
-    type Error = ConversionError;
+    type Error = <u64 as TryFromVal<E, RawVal>>::Error;
     fn try_into_val(self, env: &E) -> Result<u64, Self::Error> {
-        TryFrom::try_from(EnvVal {
-            env: env.clone(),
-            val: self,
-        })
+        <_ as TryFromVal<_, _>>::try_from_val(env, self)
     }
 }
 
 #[cfg(feature = "std")]
-impl<E: Env> TryFrom<EnvVal<E, RawVal>> for ScVal
+impl<E: Env> TryFromVal<E, RawVal> for ScVal
 where
-    ScObject: TryFrom<EnvVal<E, Object>>,
+    ScObject: TryFromVal<E, Object>,
 {
     type Error = ConversionError;
 
-    fn try_from(ev: EnvVal<E, RawVal>) -> Result<Self, Self::Error> {
-        let ev_clone = ev.clone();
-        let env = ev_clone.env;
-        let val = ev_clone.val;
+    fn try_from_val(env: &E, val: RawVal) -> Result<Self, Self::Error> {
         if val.is_u63() {
             Ok(ScVal::U63(unsafe { val.unchecked_as_u63() }))
         } else {
@@ -262,7 +234,7 @@ where
                     } else if tag_static.is_type(ScStatic::LedgerKeyContractCode) {
                         Ok(ScVal::Static(ScStatic::LedgerKeyContractCode))
                     } else {
-                        ev.log_err_convert::<Self>();
+                        log_err_convert::<Self>(env, &val);
                         Err(ConversionError)
                     }
                 }
diff --git a/soroban-env-common/src/lib.rs b/soroban-env-common/src/lib.rs
index 92ee2547..af9e517a 100644
--- a/soroban-env-common/src/lib.rs
+++ b/soroban-env-common/src/lib.rs
@@ -28,6 +28,7 @@ mod env;
 mod env_val;
 pub mod meta;
 mod object;
+mod option;
 mod raw_val;
 mod r#static;
 mod status;
diff --git a/soroban-env-common/src/object.rs b/soroban-env-common/src/object.rs
index 106f398d..17fd8f0c 100644
--- a/soroban-env-common/src/object.rs
+++ b/soroban-env-common/src/object.rs
@@ -1,6 +1,6 @@
 use crate::{
     decl_tagged_val_wrapper_methods, xdr::ScObjectType, Env, EnvVal, RawVal, Tag, TryConvert,
-    TryIntoVal,
+    TryFromVal, TryIntoVal,
 };
 use core::fmt::Debug;
 use stellar_xdr::{ScObject, ScVal};
@@ -53,23 +53,13 @@ impl Object {
     }
 }
 
-impl<E> TryFrom<EnvVal<E, Object>> for ScObject
+impl<E> TryFromVal<E, Object> for ScObject
 where
     E: Env + TryConvert<Object, ScObject>,
 {
     type Error = E::Error;
-    fn try_from(ev: EnvVal<E, Object>) -> Result<Self, Self::Error> {
-        ev.env.convert(ev.val)
-    }
-}
-
-impl<E> TryFrom<&EnvVal<E, Object>> for ScObject
-where
-    E: Env + TryConvert<Object, ScObject>,
-{
-    type Error = E::Error;
-    fn try_from(ev: &EnvVal<E, Object>) -> Result<Self, Self::Error> {
-        ev.env.convert(ev.val)
+    fn try_from_val(env: &E, val: Object) -> Result<Self, Self::Error> {
+        env.convert(val)
     }
 }
 
@@ -93,26 +83,6 @@ where
     }
 }
 
-impl<E> TryFrom<EnvVal<E, Object>> for ScVal
-where
-    E: Env + TryConvert<Object, ScObject>,
-{
-    type Error = E::Error;
-    fn try_from(ev: EnvVal<E, Object>) -> Result<Self, Self::Error> {
-        (&ev).try_into()
-    }
-}
-
-impl<E> TryFrom<&EnvVal<E, Object>> for ScVal
-where
-    E: Env + TryConvert<Object, ScObject>,
-{
-    type Error = E::Error;
-    fn try_from(ev: &EnvVal<E, Object>) -> Result<Self, Self::Error> {
-        Ok(ScVal::Object(Some(ev.env.convert(ev.val)?)))
-    }
-}
-
 impl<'a, E> TryIntoVal<E, Object> for &'a ScVal
 where
     E: Env + TryConvert<&'a ScObject, Object>,
diff --git a/soroban-env-common/src/option.rs b/soroban-env-common/src/option.rs
new file mode 100644
index 00000000..623381e3
--- /dev/null
+++ b/soroban-env-common/src/option.rs
@@ -0,0 +1,51 @@
+use crate::{Env, IntoVal, RawVal, TryFromVal, TryIntoVal};
+
+impl<E: Env, T> TryFromVal<E, RawVal> for Option<T>
+where
+    T: TryFromVal<E, RawVal>,
+{
+    type Error = T::Error;
+
+    fn try_from_val(env: &E, val: RawVal) -> Result<Self, Self::Error> {
+        if val.is_void() {
+            Ok(None)
+        } else {
+            Ok(Some(T::try_from_val(env, val)?))
+        }
+    }
+}
+
+impl<E: Env, T> TryIntoVal<E, Option<T>> for RawVal
+where
+    T: TryFromVal<E, RawVal>,
+{
+    type Error = T::Error;
+    #[inline(always)]
+    fn try_into_val(self, env: &E) -> Result<Option<T>, Self::Error> {
+        <_ as TryFromVal<E, RawVal>>::try_from_val(env, self)
+    }
+}
+
+impl<E: Env, T> IntoVal<E, RawVal> for &Option<T>
+where
+    for<'a> &'a T: IntoVal<E, RawVal>,
+{
+    fn into_val(self, env: &E) -> RawVal {
+        match self {
+            Some(t) => t.into_val(env),
+            None => RawVal::from_void(),
+        }
+    }
+}
+
+impl<E: Env, T> IntoVal<E, RawVal> for Option<T>
+where
+    T: IntoVal<E, RawVal>,
+{
+    fn into_val(self, env: &E) -> RawVal {
+        match self {
+            Some(t) => t.into_val(env),
+            None => RawVal::from_void(),
+        }
+    }
+}
diff --git a/soroban-env-common/src/raw_val.rs b/soroban-env-common/src/raw_val.rs
index 0da92d9c..d1171366 100644
--- a/soroban-env-common/src/raw_val.rs
+++ b/soroban-env-common/src/raw_val.rs
@@ -1,6 +1,6 @@
 use stellar_xdr::{ScStatic, ScStatus, ScStatusType};
 
-use super::{BitSet, Env, EnvVal, Object, Static, Status, Symbol};
+use super::{BitSet, Env, EnvVal, IntoVal, Object, Static, Status, Symbol, TryFromVal, TryIntoVal};
 use core::{convert::Infallible, fmt::Debug};
 
 extern crate static_assertions as sa;
@@ -106,6 +106,19 @@ impl AsMut<RawVal> for RawVal {
     }
 }
 
+impl<E: Env> TryFromVal<E, RawVal> for RawVal {
+    type Error = Infallible;
+    fn try_from_val(_env: &E, val: RawVal) -> Result<Self, Self::Error> {
+        Ok(val)
+    }
+}
+
+impl<E: Env> IntoVal<E, RawVal> for RawVal {
+    fn into_val(self, _env: &E) -> RawVal {
+        self
+    }
+}
+
 // This is a 0-arg struct rather than an enum to ensure it completely compiles
 // away, the same way `()` would, while remaining a separate type to allow
 // conversion to a more-structured error code at a higher level.
@@ -184,22 +197,28 @@ macro_rules! declare_tryfrom {
                 }
             }
         }
-        impl<E: Env> TryFrom<EnvVal<E, RawVal>> for $T {
+        impl<E: Env> IntoVal<E, RawVal> for $T {
+            fn into_val(self, _env: &E) -> RawVal {
+                self.into()
+            }
+        }
+        impl<E: Env> TryFromVal<E, RawVal> for $T {
             type Error = ConversionError;
             #[inline(always)]
-            fn try_from(v: EnvVal<E, RawVal>) -> Result<Self, Self::Error> {
-                Self::try_from(v.to_raw())
+            fn try_from_val(_env: &E, val: RawVal) -> Result<Self, Self::Error> {
+                Self::try_from(val)
+            }
+        }
+        impl<E: Env> TryIntoVal<E, RawVal> for $T {
+            type Error = ConversionError;
+            fn try_into_val(self, _env: &E) -> Result<RawVal, Self::Error> {
+                Ok(self.into())
             }
         }
-        impl<E: Env> TryFrom<EnvVal<E, RawVal>> for EnvVal<E, $T> {
-            type Error = crate::ConversionError;
-            fn try_from(ev: EnvVal<E, RawVal>) -> Result<Self, Self::Error> {
-                let val: $T = ev.to_raw().try_into().map_err(|err| {
-                    ev.clone().log_err_convert::<Self>();
-                    err
-                })?;
-                let env = ev.env;
-                Ok(Self { env, val })
+        impl<E: Env> TryIntoVal<E, $T> for RawVal {
+            type Error = ConversionError;
+            fn try_into_val(self, env: &E) -> Result<$T, Self::Error> {
+                <_ as TryFromVal<E, RawVal>>::try_from_val(&env, self)
             }
         }
     };
diff --git a/soroban-env-common/src/tuple.rs b/soroban-env-common/src/tuple.rs
index 5a6e863d..c882ff48 100644
--- a/soroban-env-common/src/tuple.rs
+++ b/soroban-env-common/src/tuple.rs
@@ -7,18 +7,17 @@ use crate::{
 
 macro_rules! impl_for_tuple {
     ( $count:literal $($typ:ident $idx:tt)+ ) => {
-        impl<E: Env, $($typ),*> TryFrom<EnvVal<E, RawVal>> for ($($typ,)*)
+        impl<E: Env, $($typ),*> TryFromVal<E, RawVal> for ($($typ,)*)
         where
-            $($typ: TryFrom<EnvVal<E, RawVal>>),*
+            $($typ: TryFromVal<E, RawVal>),*
         {
             type Error = ConversionError;
 
-            fn try_from(ev: EnvVal<E, RawVal>) -> Result<Self, Self::Error> {
-                if !Object::val_is_obj_type(ev.val, ScObjectType::Vec) {
+            fn try_from_val(env: &E, val: RawVal) -> Result<Self, Self::Error> {
+                if !Object::val_is_obj_type(val, ScObjectType::Vec) {
                     return Err(ConversionError);
                 }
-                let env = ev.env.clone();
-                let vec = unsafe { Object::unchecked_from_val(ev.val) };
+                let vec = unsafe { Object::unchecked_from_val(val) };
                 let len: u32 = env.vec_len(vec).try_into()?;
                 if len != $count {
                     return Err(ConversionError);
@@ -58,14 +57,14 @@ macro_rules! impl_for_tuple {
             }
         }
 
-        impl<E: Env, $($typ),*> TryIntoVal<E,  ($($typ,)*)> for RawVal
+        impl<E: Env, $($typ),*> TryIntoVal<E, ($($typ,)*)> for RawVal
         where
-            $($typ: TryFrom<EnvVal<E, RawVal>>),*
+            $($typ: TryFromVal<E, RawVal>),*
         {
             type Error = ConversionError;
             #[inline(always)]
-            fn try_into_val(self, env: &E) -> Result< ($($typ,)*), Self::Error> {
-                EnvVal{ env: env.clone(), val: self }.try_into()
+            fn try_into_val(self, env: &E) -> Result<($($typ,)*), Self::Error> {
+                <_ as TryFromVal<_, _>>::try_from_val(env, self)
             }
         }
     };
diff --git a/soroban-env-common/src/val_wrapper.rs b/soroban-env-common/src/val_wrapper.rs
index 9d0698fd..9db33789 100644
--- a/soroban-env-common/src/val_wrapper.rs
+++ b/soroban-env-common/src/val_wrapper.rs
@@ -19,7 +19,7 @@ macro_rules! decl_tagged_val_wrapper_methods {
                 b.0
             }
         }
-        impl crate::RawValConvertible for $tagname {
+        impl $crate::RawValConvertible for $tagname {
             #[inline(always)]
             fn is_val_type(v: RawVal) -> bool {
                 v.has_tag(Tag::$tagname)
@@ -138,11 +138,11 @@ macro_rules! impl_wrapper_from {
                 Self(x.into())
             }
         }
-        impl<E: Env> TryFrom<EnvVal<E, $tagname>> for $fromty {
-            type Error = crate::ConversionError;
+        impl<E: Env> $crate::TryFromVal<E, $tagname> for $fromty {
+            type Error = $crate::ConversionError;
             #[inline(always)]
-            fn try_from(v: EnvVal<E, $tagname>) -> Result<Self, Self::Error> {
-                Self::try_from(v.to_raw())
+            fn try_from_val(_env: &E, val: $tagname) -> Result<Self, Self::Error> {
+                Self::try_from(val.to_raw())
             }
         }
     };
diff --git a/soroban-env-host/src/native_contract/base_types.rs b/soroban-env-host/src/native_contract/base_types.rs
index 1ef85df4..053e954f 100644
--- a/soroban-env-host/src/native_contract/base_types.rs
+++ b/soroban-env-host/src/native_contract/base_types.rs
@@ -1,29 +1,38 @@
 use crate::host::{Host, HostError};
 use core::cmp::Ordering;
 use soroban_env_common::xdr::ScObjectType;
-use soroban_env_common::{CheckedEnv, ConversionError, EnvVal, Object, RawVal, TryIntoVal};
+use soroban_env_common::{
+    CheckedEnv, ConversionError, EnvVal, Object, RawVal, TryFromVal, TryIntoVal,
+};
 
 #[derive(Clone)]
 pub struct BigInt(EnvVal<Host, Object>);
 
-impl TryFrom<EnvVal<Host, Object>> for BigInt {
+impl TryFromVal<Host, Object> for BigInt {
     type Error = HostError;
 
-    fn try_from(value: EnvVal<Host, Object>) -> Result<Self, Self::Error> {
-        if value.val.is_obj_type(ScObjectType::BigInt) {
-            Ok(BigInt(value))
+    fn try_from_val(env: &Host, val: Object) -> Result<Self, Self::Error> {
+        if val.is_obj_type(ScObjectType::BigInt) {
+            Ok(BigInt(val.in_env(env)))
         } else {
             Err(ConversionError.into())
         }
     }
 }
 
-impl TryFrom<EnvVal<Host, RawVal>> for BigInt {
+impl TryFromVal<Host, RawVal> for BigInt {
     type Error = HostError;
 
-    fn try_from(value: EnvVal<Host, RawVal>) -> Result<Self, Self::Error> {
-        let env_obj: EnvVal<Host, Object> = value.try_into()?;
-        env_obj.try_into()
+    fn try_from_val(env: &Host, val: RawVal) -> Result<Self, Self::Error> {
+        <_ as TryFromVal<_, Object>>::try_from_val(env, val.try_into()?)
+    }
+}
+
+impl TryIntoVal<Host, BigInt> for RawVal {
+    type Error = HostError;
+
+    fn try_into_val(self, env: &Host) -> Result<BigInt, Self::Error> {
+        <_ as TryFromVal<_, RawVal>>::try_from_val(env, self.try_into()?)
     }
 }
 
@@ -46,7 +55,7 @@ impl core::ops::Add for BigInt {
 
     fn add(self, rhs: Self) -> Self::Output {
         let res = self.0.env.bigint_add(self.0.val, rhs.0.val)?;
-        res.in_env(&self.0.env).try_into()
+        BigInt::try_from_val(&self.0.env, res)
     }
 }
 
@@ -55,14 +64,14 @@ impl core::ops::Sub for BigInt {
 
     fn sub(self, rhs: Self) -> Self::Output {
         let res = self.0.env.bigint_sub(self.0.val, rhs.0.val)?;
-        res.in_env(&self.0.env).try_into()
+        BigInt::try_from_val(&self.0.env, res)
     }
 }
 
 impl BigInt {
     pub fn from_u64(env: &Host, x: u64) -> Result<Self, HostError> {
         let res = env.bigint_from_u64(x)?;
-        res.in_env(env).try_into()
+        BigInt::try_from_val(env, res)
     }
 
     pub fn compare(&self, other: &BigInt) -> Result<Ordering, HostError> {
@@ -75,24 +84,31 @@ impl BigInt {
 #[derive(Clone)]
 pub struct Bytes(EnvVal<Host, Object>);
 
-impl TryFrom<EnvVal<Host, Object>> for Bytes {
+impl TryFromVal<Host, Object> for Bytes {
     type Error = HostError;
 
-    fn try_from(value: EnvVal<Host, Object>) -> Result<Self, Self::Error> {
-        if value.val.is_obj_type(ScObjectType::Bytes) {
-            Ok(Bytes(value))
+    fn try_from_val(env: &Host, val: Object) -> Result<Self, Self::Error> {
+        if val.is_obj_type(ScObjectType::Bytes) {
+            Ok(Bytes(val.in_env(env)))
         } else {
             Err(ConversionError.into())
         }
     }
 }
 
-impl TryFrom<EnvVal<Host, RawVal>> for Bytes {
+impl TryFromVal<Host, RawVal> for Bytes {
     type Error = HostError;
 
-    fn try_from(value: EnvVal<Host, RawVal>) -> Result<Self, Self::Error> {
-        let env_obj: EnvVal<Host, Object> = value.try_into()?;
-        env_obj.try_into()
+    fn try_from_val(env: &Host, val: RawVal) -> Result<Self, Self::Error> {
+        <_ as TryFromVal<_, Object>>::try_from_val(env, val.try_into()?)
+    }
+}
+
+impl TryIntoVal<Host, Bytes> for RawVal {
+    type Error = HostError;
+
+    fn try_into_val(self, env: &Host) -> Result<Bytes, Self::Error> {
+        <_ as TryFromVal<_, RawVal>>::try_from_val(env, self.try_into()?)
     }
 }
 
@@ -113,26 +129,32 @@ impl From<Bytes> for Object {
 #[derive(Clone)]
 pub struct BytesN<const N: u32>(EnvVal<Host, Object>);
 
-impl<const N: u32> TryFrom<EnvVal<Host, Object>> for BytesN<N> {
+impl<const N: u32> TryFromVal<Host, Object> for BytesN<N> {
     type Error = HostError;
 
-    fn try_from(value: EnvVal<Host, Object>) -> Result<Self, Self::Error> {
-        let bin = value.val;
-        let len: u32 = value.env.binary_len(bin)?.try_into()?;
+    fn try_from_val(env: &Host, val: Object) -> Result<Self, Self::Error> {
+        let len: u32 = env.binary_len(val)?.try_into()?;
         if len == N {
-            Ok(Self(bin.in_env(&value.env)))
+            Ok(Self(val.in_env(env)))
         } else {
             Err(ConversionError.into())
         }
     }
 }
 
-impl<const N: u32> TryFrom<EnvVal<Host, RawVal>> for BytesN<N> {
+impl<const N: u32> TryFromVal<Host, RawVal> for BytesN<N> {
     type Error = HostError;
 
-    fn try_from(value: EnvVal<Host, RawVal>) -> Result<Self, Self::Error> {
-        let env_obj: EnvVal<Host, Object> = value.try_into()?;
-        env_obj.try_into()
+    fn try_from_val(env: &Host, val: RawVal) -> Result<Self, Self::Error> {
+        <_ as TryFromVal<_, Object>>::try_from_val(env, val.try_into()?)
+    }
+}
+
+impl<const N: u32> TryIntoVal<Host, BytesN<N>> for RawVal {
+    type Error = HostError;
+
+    fn try_into_val(self, env: &Host) -> Result<BytesN<N>, Self::Error> {
+        <_ as TryFromVal<_, RawVal>>::try_from_val(env, self.try_into()?)
     }
 }
 
@@ -160,24 +182,31 @@ impl<const N: u32> BytesN<N> {
 #[derive(Clone)]
 pub struct Map(EnvVal<Host, Object>);
 
-impl TryFrom<EnvVal<Host, Object>> for Map {
+impl TryFromVal<Host, Object> for Map {
     type Error = HostError;
 
-    fn try_from(value: EnvVal<Host, Object>) -> Result<Self, Self::Error> {
-        if value.val.is_obj_type(ScObjectType::Map) {
-            Ok(Map(value))
+    fn try_from_val(env: &Host, val: Object) -> Result<Self, Self::Error> {
+        if val.is_obj_type(ScObjectType::Map) {
+            Ok(Map(val.in_env(env)))
         } else {
             Err(ConversionError.into())
         }
     }
 }
 
-impl TryFrom<EnvVal<Host, RawVal>> for Map {
+impl TryFromVal<Host, RawVal> for Map {
+    type Error = HostError;
+
+    fn try_from_val(env: &Host, val: RawVal) -> Result<Self, Self::Error> {
+        <_ as TryFromVal<_, Object>>::try_from_val(env, val.try_into()?)
+    }
+}
+
+impl TryIntoVal<Host, Map> for RawVal {
     type Error = HostError;
 
-    fn try_from(value: EnvVal<Host, RawVal>) -> Result<Self, Self::Error> {
-        let env_obj: EnvVal<Host, Object> = value.try_into()?;
-        env_obj.try_into()
+    fn try_into_val(self, env: &Host) -> Result<Map, Self::Error> {
+        <_ as TryFromVal<_, RawVal>>::try_from_val(env, self.try_into()?)
     }
 }
 
@@ -201,17 +230,17 @@ impl Map {
         Ok(Self(map.in_env(env)))
     }
 
-    pub fn get<K: TryIntoVal<Host, RawVal>, V: TryFrom<EnvVal<Host, RawVal>>>(
+    pub fn get<K: TryIntoVal<Host, RawVal>, V: TryFromVal<Host, RawVal>>(
         &self,
         k: K,
     ) -> Result<V, HostError>
     where
         HostError: From<<K as TryIntoVal<Host, RawVal>>::Error>,
-        HostError: From<<V as TryFrom<EnvVal<Host, RawVal>>>::Error>,
+        HostError: From<<V as TryFromVal<Host, RawVal>>::Error>,
     {
         let k_rv = k.try_into_val(&self.0.env)?;
         let v_rv = self.0.env.map_get(self.0.val, k_rv)?;
-        Ok(v_rv.in_env(&self.0.env).try_into()?)
+        Ok(V::try_from_val(&self.0.env, v_rv)?)
     }
 
     pub fn set<K: TryIntoVal<Host, RawVal>, V: TryIntoVal<Host, RawVal>>(
@@ -233,24 +262,31 @@ impl Map {
 #[derive(Clone)]
 pub struct Vec(EnvVal<Host, Object>);
 
-impl TryFrom<EnvVal<Host, Object>> for Vec {
+impl TryFromVal<Host, Object> for Vec {
     type Error = HostError;
 
-    fn try_from(value: EnvVal<Host, Object>) -> Result<Self, Self::Error> {
-        if value.val.is_obj_type(ScObjectType::Vec) {
-            Ok(Vec(value))
+    fn try_from_val(env: &Host, val: Object) -> Result<Self, Self::Error> {
+        if val.is_obj_type(ScObjectType::Vec) {
+            Ok(Vec(val.in_env(env)))
         } else {
             Err(ConversionError.into())
         }
     }
 }
 
-impl TryFrom<EnvVal<Host, RawVal>> for Vec {
+impl TryFromVal<Host, RawVal> for Vec {
+    type Error = HostError;
+
+    fn try_from_val(env: &Host, val: RawVal) -> Result<Self, Self::Error> {
+        <_ as TryFromVal<_, Object>>::try_from_val(env, val.try_into()?)
+    }
+}
+
+impl TryIntoVal<Host, Vec> for RawVal {
     type Error = HostError;
 
-    fn try_from(value: EnvVal<Host, RawVal>) -> Result<Self, Self::Error> {
-        let env_obj: EnvVal<Host, Object> = value.try_into()?;
-        env_obj.try_into()
+    fn try_into_val(self, env: &Host) -> Result<Vec, Self::Error> {
+        <_ as TryFromVal<_, RawVal>>::try_from_val(env, self.try_into()?)
     }
 }
 
@@ -274,17 +310,17 @@ impl Vec {
         Ok(Self(vec.in_env(env)))
     }
 
-    pub fn get<T: TryFrom<EnvVal<Host, RawVal>>>(&self, i: u32) -> Result<T, HostError>
+    pub fn get<T: TryFromVal<Host, RawVal>>(&self, i: u32) -> Result<T, HostError>
     where
-        HostError: From<<T as TryFrom<EnvVal<Host, RawVal>>>::Error>,
+        HostError: From<<T as TryFromVal<Host, RawVal>>::Error>,
     {
         let rv = self.0.env.vec_get(self.0.val, i.into())?;
-        Ok(rv.in_env(&self.0.env).try_into()?)
+        Ok(T::try_from_val(&self.0.env, rv)?)
     }
 
     pub fn len(&self) -> Result<u32, HostError> {
         let rv = self.0.env.vec_len(self.0.val)?;
-        Ok(rv.in_env(&self.0.env).try_into()?)
+        Ok(u32::try_from_val(&self.0.env, rv)?)
     }
 
     pub fn push<T: TryIntoVal<Host, RawVal>>(&mut self, x: T) -> Result<(), HostError>
diff --git a/soroban-env-host/src/native_contract/token/admin.rs b/soroban-env-host/src/native_contract/token/admin.rs
index 0409b10b..919d5522 100644
--- a/soroban-env-host/src/native_contract/token/admin.rs
+++ b/soroban-env-host/src/native_contract/token/admin.rs
@@ -6,7 +6,7 @@ use crate::native_contract::token::public_types::{
 };
 use crate::native_contract::token::storage_types::DataKey;
 use core::cmp::Ordering;
-use soroban_env_common::{CheckedEnv, TryIntoVal};
+use soroban_env_common::{CheckedEnv, TryFromVal, TryIntoVal};
 
 pub fn has_administrator(e: &Host) -> Result<bool, Error> {
     let key = DataKey::Admin;
@@ -17,7 +17,7 @@ pub fn has_administrator(e: &Host) -> Result<bool, Error> {
 fn read_administrator(e: &Host) -> Result<Identifier, Error> {
     let key = DataKey::Admin;
     let rv = e.get_contract_data(key.try_into_val(e)?)?;
-    Ok(rv.in_env(e).try_into()?)
+    Ok(Identifier::try_from_val(e, rv)?)
 }
 
 pub fn to_administrator_authorization(
@@ -27,7 +27,7 @@ pub fn to_administrator_authorization(
     let admin = read_administrator(e)?;
     match (admin, auth) {
         (Identifier::Contract(admin_id), Authorization::Contract) => {
-            let invoker_id: BytesN<32> = e.get_invoking_contract()?.in_env(e).try_into()?;
+            let invoker_id: BytesN<32> = e.get_invoking_contract()?.to_raw().try_into_val(e)?;
             if admin_id.compare(&invoker_id)? != Ordering::Equal {
                 Err(Error::ContractError)
             } else {
diff --git a/soroban-env-host/src/native_contract/token/allowance.rs b/soroban-env-host/src/native_contract/token/allowance.rs
index 1b8acc2d..d7d8ae88 100644
--- a/soroban-env-host/src/native_contract/token/allowance.rs
+++ b/soroban-env-host/src/native_contract/token/allowance.rs
@@ -9,7 +9,7 @@ use soroban_env_common::{CheckedEnv, TryIntoVal};
 pub fn read_allowance(e: &Host, from: Identifier, spender: Identifier) -> Result<BigInt, Error> {
     let key = DataKey::Allowance(AllowanceDataKey { from, spender });
     if let Ok(allowance) = e.get_contract_data(key.try_into_val(e)?) {
-        Ok(allowance.in_env(e).try_into()?)
+        Ok(allowance.try_into_val(e)?)
     } else {
         Ok(BigInt::from_u64(e, 0)?)
     }
diff --git a/soroban-env-host/src/native_contract/token/balance.rs b/soroban-env-host/src/native_contract/token/balance.rs
index 62a153ba..8abd0e88 100644
--- a/soroban-env-host/src/native_contract/token/balance.rs
+++ b/soroban-env-host/src/native_contract/token/balance.rs
@@ -9,7 +9,7 @@ use soroban_env_common::{CheckedEnv, TryIntoVal};
 pub fn read_balance(e: &Host, id: Identifier) -> Result<BigInt, Error> {
     let key = DataKey::Balance(id);
     if let Ok(balance) = e.get_contract_data(key.try_into_val(e)?) {
-        Ok(balance.in_env(e).try_into()?)
+        Ok(balance.try_into_val(e)?)
     } else {
         Ok(BigInt::from_u64(e, 0)?)
     }
diff --git a/soroban-env-host/src/native_contract/token/metadata.rs b/soroban-env-host/src/native_contract/token/metadata.rs
index 99e496de..474de546 100644
--- a/soroban-env-host/src/native_contract/token/metadata.rs
+++ b/soroban-env-host/src/native_contract/token/metadata.rs
@@ -19,7 +19,7 @@ pub fn write_decimal(e: &Host, d: u8) -> Result<(), Error> {
 pub fn read_name(e: &Host) -> Result<Bytes, Error> {
     let key = DataKey::Name;
     let rv = e.get_contract_data(key.try_into_val(e)?)?;
-    Ok(rv.in_env(e).try_into()?)
+    Ok(rv.try_into_val(e)?)
 }
 
 pub fn write_name(e: &Host, d: Bytes) -> Result<(), Error> {
@@ -31,7 +31,7 @@ pub fn write_name(e: &Host, d: Bytes) -> Result<(), Error> {
 pub fn read_symbol(e: &Host) -> Result<Bytes, Error> {
     let key = DataKey::Symbol;
     let rv = e.get_contract_data(key.try_into_val(e)?)?;
-    Ok(rv.in_env(e).try_into()?)
+    Ok(rv.try_into_val(e)?)
 }
 
 pub fn write_symbol(e: &Host, d: Bytes) -> Result<(), Error> {
diff --git a/soroban-env-host/src/native_contract/token/nonce.rs b/soroban-env-host/src/native_contract/token/nonce.rs
index 5a9789e4..5edde0d4 100644
--- a/soroban-env-host/src/native_contract/token/nonce.rs
+++ b/soroban-env-host/src/native_contract/token/nonce.rs
@@ -8,7 +8,7 @@ use soroban_env_common::{CheckedEnv, TryIntoVal};
 pub fn read_nonce(e: &Host, id: Identifier) -> Result<BigInt, Error> {
     let key = DataKey::Nonce(id);
     if let Ok(nonce) = e.get_contract_data(key.try_into_val(e)?) {
-        Ok(nonce.in_env(e).try_into()?)
+        Ok(nonce.try_into_val(e)?)
     } else {
         Ok(BigInt::from_u64(e, 0)?)
     }
diff --git a/soroban-env-host/src/native_contract/token/public_types.rs b/soroban-env-host/src/native_contract/token/public_types.rs
index ddea3f30..eeab09c8 100644
--- a/soroban-env-host/src/native_contract/token/public_types.rs
+++ b/soroban-env-host/src/native_contract/token/public_types.rs
@@ -41,7 +41,7 @@ impl KeyedAuthorization {
     pub fn get_identifier(&self, env: &Host) -> Result<Identifier, Error> {
         Ok(match self {
             KeyedAuthorization::Contract => {
-                Identifier::Contract(env.get_invoking_contract()?.in_env(env).try_into()?)
+                Identifier::Contract(env.get_invoking_contract()?.to_raw().try_into_val(env)?)
             }
             KeyedAuthorization::Ed25519(kea) => Identifier::Ed25519(kea.public_key.clone()),
             KeyedAuthorization::Account(kaa) => Identifier::Account(kaa.public_key.clone()),
diff --git a/soroban-native-sdk-macros/src/derive_fn.rs b/soroban-native-sdk-macros/src/derive_fn.rs
index 2704bc13..4d86e22d 100644
--- a/soroban-native-sdk-macros/src/derive_fn.rs
+++ b/soroban-native-sdk-macros/src/derive_fn.rs
@@ -31,7 +31,7 @@ pub fn derive_contract_function_set<'a>(
             let func_call = quote! {
                 #discriminant_ident => {
                     if args.len() == #num_args {
-                        #(let #args: #arg_types = args.get(#arg_indices).cloned().ok_or(soroban_env_common::ConversionError)?.in_env(host).try_into()?;)*
+                        #(let #args: #arg_types = args.get(#arg_indices).cloned().ok_or(soroban_env_common::ConversionError)?.try_into_val(host)?;)*
                         Ok(Self::#ident(host, #(#args,)*)?.try_into_val(host)?)
                     } else {
                         Err(host.err_general("wrong number of args"))
diff --git a/soroban-native-sdk-macros/src/derive_type.rs b/soroban-native-sdk-macros/src/derive_type.rs
index 555b8439..bae9cbbc 100644
--- a/soroban-native-sdk-macros/src/derive_type.rs
+++ b/soroban-native-sdk-macros/src/derive_type.rs
@@ -22,23 +22,22 @@ pub fn derive_type_struct(ident: &Ident, data: &DataStruct) -> TokenStream2 {
         .multiunzip();
 
     quote! {
-        impl TryFrom<soroban_env_common::EnvVal<crate::Host, soroban_env_common::Object>> for #ident {
+        impl soroban_env_common::TryFromVal<crate::Host, soroban_env_common::Object> for #ident {
             type Error = crate::HostError;
 
-            fn try_from(value: soroban_env_common::EnvVal<crate::Host, soroban_env_common::Object>) -> Result<Self, Self::Error> {
-                let map = Map::try_from(value)?;
+            fn try_from_val(env: &crate::Host, val: soroban_env_common::Object) -> Result<Self, Self::Error> {
+                let map = Map::try_from_val(env, val)?;
                 Ok(Self {
                     #(#names: map.get(#map_keys)?,)*
                 })
             }
         }
 
-        impl TryFrom<soroban_env_common::EnvVal<crate::Host, soroban_env_common::RawVal>> for #ident {
+        impl soroban_env_common::TryFromVal<crate::Host, soroban_env_common::RawVal> for #ident {
             type Error = crate::HostError;
 
-            fn try_from(value: soroban_env_common::EnvVal<crate::Host, soroban_env_common::RawVal>) -> Result<Self, Self::Error> {
-                let env_obj: soroban_env_common::EnvVal<crate::Host, soroban_env_common::Object> = value.try_into()?;
-                env_obj.try_into()
+            fn try_from_val(env: &crate::Host, val: soroban_env_common::RawVal) -> Result<Self, Self::Error> {
+                <_ as soroban_env_common::TryFromVal<_, soroban_env_common::Object>>::try_from_val(env, val.try_into()?)
             }
         }
 
@@ -51,6 +50,14 @@ pub fn derive_type_struct(ident: &Ident, data: &DataStruct) -> TokenStream2 {
                 map.try_into_val(env)
             }
         }
+
+        impl TryIntoVal<crate::Host, #ident> for soroban_env_common::RawVal {
+            type Error = crate::HostError;
+
+            fn try_into_val(self, env: &crate::Host) -> Result<#ident, Self::Error> {
+                <_ as soroban_env_common::TryFromVal<_, _>>::try_from_val(env, self)
+            }
+        }
     }
 }
 
@@ -102,12 +109,12 @@ pub fn derive_type_enum(ident: &Ident, data: &DataEnum) -> TokenStream2 {
         quote! { #(#compile_errors)* }
     } else {
         quote! {
-            impl TryFrom<soroban_env_common::EnvVal<crate::Host, soroban_env_common::Object>> for #ident {
+            impl soroban_env_common::TryFromVal<crate::Host, soroban_env_common::Object> for #ident {
                 type Error = crate::HostError;
 
-                fn try_from(value: soroban_env_common::EnvVal<crate::Host, soroban_env_common::Object>) -> Result<Self, Self::Error> {
+                fn try_from_val(env: &crate::Host, val: soroban_env_common::Object) -> Result<Self, Self::Error> {
                     #(#consts;)*
-                    let vec = crate::native_contract::base_types::Vec::try_from(value)?;
+                    let vec = crate::native_contract::base_types::Vec::try_from_val(env, val)?;
                     let discriminant: soroban_env_common::Symbol = vec.get(0)?;
                     match discriminant.to_raw().get_payload() {
                         #(#froms,)*
@@ -116,12 +123,11 @@ pub fn derive_type_enum(ident: &Ident, data: &DataEnum) -> TokenStream2 {
                 }
             }
 
-            impl TryFrom<soroban_env_common::EnvVal<crate::Host, soroban_env_common::RawVal>> for #ident {
+            impl soroban_env_common::TryFromVal<crate::Host, soroban_env_common::RawVal> for #ident {
                 type Error = crate::HostError;
 
-                fn try_from(value: soroban_env_common::EnvVal<crate::Host, soroban_env_common::RawVal>) -> Result<Self, Self::Error> {
-                    let env_obj: soroban_env_common::EnvVal<crate::Host, soroban_env_common::Object> = value.try_into()?;
-                    env_obj.try_into()
+                fn try_from_val(env: &crate::Host, val: soroban_env_common::RawVal) -> Result<Self, Self::Error> {
+                    <_ as soroban_env_common::TryFromVal<_, soroban_env_common::Object>>::try_from_val(env, val.try_into()?)
                 }
             }
 
@@ -137,6 +143,14 @@ pub fn derive_type_enum(ident: &Ident, data: &DataEnum) -> TokenStream2 {
                     vec.try_into_val(env)
                 }
             }
+
+            impl TryIntoVal<crate::Host, #ident> for soroban_env_common::RawVal {
+                type Error = crate::HostError;
+
+                fn try_into_val(self, env: &crate::Host) -> Result<#ident, Self::Error> {
+                    <_ as soroban_env_common::TryFromVal<_, _>>::try_from_val(env, self)
+                }
+            }
         }
     }
 }


Test patch:
diff --git a/soroban-env-common/tests/option.rs b/soroban-env-common/tests/option.rs
new file mode 100644
index 00000000..58d960cd
--- /dev/null
+++ b/soroban-env-common/tests/option.rs
@@ -0,0 +1,30 @@
+use soroban_env_host::Host;
+
+use soroban_env_common::{IntoVal, RawVal, Static, TryIntoVal};
+use stellar_xdr::ScStatic;
+
+#[test]
+fn some() {
+    let host = Host::default();
+
+    let some = Some(1u32);
+    let val: RawVal = some.into_val(&host);
+    assert!(val.is::<u32>());
+    let u32: u32 = val.try_into_val(&host).unwrap();
+    assert_eq!(u32, 1);
+
+    assert_eq!(some, val.try_into_val(&host).unwrap());
+}
+
+#[test]
+fn none() {
+    let host = Host::default();
+
+    let none: Option<u32> = None;
+    let val: RawVal = none.into_val(&host);
+    assert!(val.is::<Static>());
+    let r#static: Static = val.try_into_val(&host).unwrap();
+    assert!(r#static.is_type(ScStatic::Void));
+
+    assert_eq!(none, val.try_into_val(&host).unwrap());
+}
diff --git a/soroban-env-host/src/test/basic.rs b/soroban-env-host/src/test/basic.rs
index 61e5badb..4ca8a2fd 100644
--- a/soroban-env-host/src/test/basic.rs
+++ b/soroban-env-host/src/test/basic.rs
@@ -15,7 +15,7 @@ fn u64_roundtrip() -> Result<(), HostError> {
     let obj: Object = v.try_into()?;
     assert!(obj.is_obj_type(ScObjectType::U64));
     assert_eq!(obj.get_handle(), 0);
-    let j = u64::try_from(v.in_env(&host))?;
+    let j = u64::try_from_val(&host, v)?;
     assert_eq!(u, j);
 
     let u2: u64 = u64::MAX; // This will be treated as a ScVal::Object::U64
@@ -23,7 +23,7 @@ fn u64_roundtrip() -> Result<(), HostError> {
     let obj: Object = v2.try_into()?;
     assert!(obj.is_obj_type(ScObjectType::U64));
     assert_eq!(obj.get_handle(), 1);
-    let k = u64::try_from(v2.in_env(&host))?;
+    let k = u64::try_from_val(&host, v2)?;
     assert_eq!(u2, k);
     Ok(())
 }
@@ -33,7 +33,7 @@ fn i64_roundtrip() -> Result<(), HostError> {
     let host = Host::default();
     let i: i64 = 12345_i64; // Will be treated as ScVal::I64
     let v: RawVal = i.into_val(&host);
-    let j = i64::try_from(v.in_env(&host))?;
+    let j = i64::try_from_val(&host, v)?;
     assert_eq!(i, j);
 
     let i2: i64 = -13234_i64; // WIll be treated as ScVal::Object::I64
@@ -41,7 +41,7 @@ fn i64_roundtrip() -> Result<(), HostError> {
     let obj: Object = v2.try_into()?;
     assert!(obj.is_obj_type(ScObjectType::I64));
     assert_eq!(obj.get_handle(), 0);
-    let k = i64::try_from(v2.in_env(&host))?;
+    let k = i64::try_from_val(&host, v2)?;
     assert_eq!(i2, k);
     Ok(())
 }