From 56c26eea03fac28bfaeb882b6d03e2b52cc9697f Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 15 Jul 2022 13:42:43 -0700 Subject: [PATCH 01/65] wip --- Makefile | 3 ++ src/lib.rs | 5 ++ src/scval.rs | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 src/scval.rs diff --git a/Makefile b/Makefile index 9f782275..0d2667d9 100644 --- a/Makefile +++ b/Makefile @@ -77,3 +77,6 @@ $(XDR_FILES_LOCAL_NEXT): reset-xdr: rm -f xdr/*/*.x $(MAKE) build + +fmt: + cargo fmt --all diff --git a/src/lib.rs b/src/lib.rs index 28f06b19..c44dc6b4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,3 +10,8 @@ pub use curr::*; mod next; #[cfg(feature = "next")] pub use next::*; + +#[cfg(feature = "next")] +mod scval; +#[cfg(feature = "next")] +pub use scval::*; diff --git a/src/scval.rs b/src/scval.rs new file mode 100644 index 00000000..638e8e2d --- /dev/null +++ b/src/scval.rs @@ -0,0 +1,147 @@ +use crate::{Hash, ScHash, PublicKey, ScObject, ScStatic, ScStatus, ScVal}; + +impl From for ScVal { + fn from(v: ScStatic) -> Self { + Self::Static(v) + } +} + +impl From for ScVal { + fn from(v: ScObject) -> Self { + ScVal::Object(Some(v)) + } +} + +impl From for ScVal { + fn from(v: ScStatus) -> Self { + ScVal::Status(v) + } +} + +impl From for ScVal { + fn from(v: i32) -> ScVal { + ScVal::I32(v) + } +} + +impl From for ScVal { + fn from(v: u32) -> ScVal { + ScVal::U32(v) + } +} + +impl From for ScVal { + fn from(v: i64) -> ScVal { + if v < 0 { + ScObject::I64(v).into() + } else { + ScVal::U63(v) + } + } +} + +impl From for ScVal { + fn from(v: u64) -> ScVal { + ScObject::U64(v).into() + } +} + +impl From<()> for ScVal { + fn from(_: ()) -> Self { + ScStatic::Void.into() + } +} + +impl From for ScVal { + fn from(v: bool) -> Self { + if v { ScStatic::True } else { ScStatic::False }.into() + } +} + +impl From for ScObject { + fn from(v: i64) -> ScObject { + ScObject::I64(v) + } +} + +impl From for ScObject { + fn from(v: u64) -> ScObject { + ScObject::U64(v) + } +} + +impl From for ScObject { + fn from(v: ScHash) -> Self { + ScObject::Hash(v) + } +} + +impl From for ScVal { + fn from(v: ScHash) -> Self { + <_ as Into>::into(v).into() + } +} + +impl From for ScHash { + fn from(v: Hash) -> Self { + ScHash::SchashSha256(v) + } +} + +impl From for ScObject { + fn from(v: Hash) -> Self { + <_ as Into>::into(v).into() + } +} + +impl From for ScVal { + fn from(v: Hash) -> Self { + <_ as Into>::into(v).into() + } +} + +impl From for ScObject { + fn from(v: PublicKey) -> Self { + ScObject::PublicKey(v) + } +} + +impl From for ScVal { + fn from(v: PublicKey) -> Self { + <_ as Into>::into(v).into() + } +} + +// Vec(ScVec), +// Map(ScMap), +// Binary(VecM), +// BigInt(ScBigInt), + +// impl ToScVal for &str { +// fn to_scval(&self) -> Result { +// let bytes: Vec = self.as_bytes().iter().cloned().collect(); +// Ok(ScVal::Symbol(bytes.try_into().map_err(|_| ())?)) +// } +// } + +// impl FromScVal for ScVal { +// fn from_scval(&self) -> Result { +// match self { +// ScVal::Static(ScStatic::False) => Ok(false), +// ScVal::Static(ScStatic::True) => Ok(true), +// _ => Err(()), +// } +// } +// } + +impl From> for ScVal +where + T: Into, +{ + fn from(v: Option) -> Self { + match v { + Some(v) => v.into(), + None => ().into(), + } + } +} From 52bdeacd5dbdb216d01cdc33332b3314be4fea19 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 15 Jul 2022 14:17:35 -0700 Subject: [PATCH 02/65] wip --- src/scval.rs | 66 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/src/scval.rs b/src/scval.rs index 638e8e2d..d99cbd76 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -1,4 +1,4 @@ -use crate::{Hash, ScHash, PublicKey, ScObject, ScStatic, ScStatus, ScVal}; +use crate::{Hash, PublicKey, ScHash, ScObject, ScStatic, ScStatus, ScVal}; impl From for ScVal { fn from(v: ScStatic) -> Self { @@ -112,32 +112,44 @@ impl From for ScVal { } } -// Vec(ScVec), -// Map(ScMap), -// Binary(VecM), -// BigInt(ScBigInt), - -// impl ToScVal for &str { -// fn to_scval(&self) -> Result { -// let bytes: Vec = self.as_bytes().iter().cloned().collect(); -// Ok(ScVal::Symbol(bytes.try_into().map_err(|_| ())?)) -// } -// } - -// impl FromScVal for ScVal { -// fn from_scval(&self) -> Result { -// match self { -// ScVal::Static(ScStatic::False) => Ok(false), -// ScVal::Static(ScStatic::True) => Ok(true), -// _ => Err(()), -// } -// } -// } - -impl From> for ScVal -where - T: Into, -{ +#[cfg(feature = "alloc")] +impl TryFrom<&str> for ScVal { + type Error = (); + fn try_from(v: &str) -> Result { + Ok(ScVal::Symbol(v.try_into().map_err(|_| ())?)) + } +} + +#[cfg(not(feature = "alloc"))] +impl TryFrom<&'static str> for ScVal { + type Error = (); + fn try_from(v: &'static str) -> Result { + Ok(ScVal::Symbol(v.try_into().map_err(|_| ())?)) + } +} + +#[cfg(feature = "alloc")] +impl TryFrom for ScVal { + type Error = (); + fn try_from(v: String) -> Result { + Ok(ScVal::Symbol(v.try_into().map_err(|_| ())?)) + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&String> for ScVal { + type Error = (); + fn try_from(v: &String) -> Result { + Ok(ScVal::Symbol(v.try_into().map_err(|_| ())?)) + } +} + +// TODO: Vec(ScVec), +// TODO: Map(ScMap), +// TODO: Binary(VecM), +// TODO: BigInt(ScBigInt), + +impl> From> for ScVal { fn from(v: Option) -> Self { match v { Some(v) => v.into(), From dbf46ff1988f0d488802d59df8b06d2dfa595ee5 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 15 Jul 2022 14:55:14 -0700 Subject: [PATCH 03/65] binary --- src/scval.rs | 50 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/src/scval.rs b/src/scval.rs index d99cbd76..44d01f6a 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -1,5 +1,10 @@ use crate::{Hash, PublicKey, ScHash, ScObject, ScStatic, ScStatus, ScVal}; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +extern crate alloc; +#[cfg(all(not(feature = "std"), feature = "alloc"))] +use alloc::{string::String, vec::Vec}; + impl From for ScVal { fn from(v: ScStatic) -> Self { Self::Static(v) @@ -112,6 +117,22 @@ impl From for ScVal { } } +#[cfg(feature = "alloc")] +impl TryFrom for ScVal { + type Error = (); + fn try_from(v: String) -> Result { + Ok(ScVal::Symbol(v.try_into().map_err(|_| ())?)) + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&String> for ScVal { + type Error = (); + fn try_from(v: &String) -> Result { + Ok(ScVal::Symbol(v.try_into().map_err(|_| ())?)) + } +} + #[cfg(feature = "alloc")] impl TryFrom<&str> for ScVal { type Error = (); @@ -129,24 +150,39 @@ impl TryFrom<&'static str> for ScVal { } #[cfg(feature = "alloc")] -impl TryFrom for ScVal { +impl TryFrom> for ScObject { type Error = (); - fn try_from(v: String) -> Result { - Ok(ScVal::Symbol(v.try_into().map_err(|_| ())?)) + fn try_from(v: Vec) -> Result { + Ok(ScObject::Binary(v.try_into().map_err(|_| ())?)) } } #[cfg(feature = "alloc")] -impl TryFrom<&String> for ScVal { +impl TryFrom<&Vec> for ScObject { type Error = (); - fn try_from(v: &String) -> Result { - Ok(ScVal::Symbol(v.try_into().map_err(|_| ())?)) + fn try_from(v: &Vec) -> Result { + Ok(ScObject::Binary(v.try_into().map_err(|_| ())?)) + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&[u8]> for ScObject { + type Error = (); + fn try_from(v: &[u8]) -> Result { + Ok(ScObject::Binary(v.try_into().map_err(|_| ())?)) + } +} + +#[cfg(not(feature = "alloc"))] +impl TryFrom<&'static [u8]> for ScObject { + type Error = (); + fn try_from(v: &'static [u8]) -> Result { + Ok(ScObject::Binary(v.try_into().map_err(|_| ())?)) } } // TODO: Vec(ScVec), // TODO: Map(ScMap), -// TODO: Binary(VecM), // TODO: BigInt(ScBigInt), impl> From> for ScVal { From 29f18c96059d012043a1859e71aee2c1767b9cf0 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 15 Jul 2022 15:02:31 -0700 Subject: [PATCH 04/65] additional binary --- src/scval.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/scval.rs b/src/scval.rs index 44d01f6a..a2569c20 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -157,6 +157,14 @@ impl TryFrom> for ScObject { } } +#[cfg(feature = "alloc")] +impl TryFrom> for ScVal { + type Error = (); + fn try_from(v: Vec) -> Result { + Ok(<_ as TryInto>::try_into(v)?.into()) + } +} + #[cfg(feature = "alloc")] impl TryFrom<&Vec> for ScObject { type Error = (); @@ -165,6 +173,14 @@ impl TryFrom<&Vec> for ScObject { } } +#[cfg(feature = "alloc")] +impl TryFrom<&Vec> for ScVal { + type Error = (); + fn try_from(v: &Vec) -> Result { + Ok(<_ as TryInto>::try_into(v)?.into()) + } +} + #[cfg(feature = "alloc")] impl TryFrom<&[u8]> for ScObject { type Error = (); @@ -173,6 +189,14 @@ impl TryFrom<&[u8]> for ScObject { } } +#[cfg(feature = "alloc")] +impl TryFrom<&[u8]> for ScVal { + type Error = (); + fn try_from(v: &[u8]) -> Result { + Ok(<_ as TryInto>::try_into(v)?.into()) + } +} + #[cfg(not(feature = "alloc"))] impl TryFrom<&'static [u8]> for ScObject { type Error = (); @@ -181,6 +205,14 @@ impl TryFrom<&'static [u8]> for ScObject { } } +#[cfg(not(feature = "alloc"))] +impl TryFrom<&'static [u8]> for ScVal { + type Error = (); + fn try_from(v: &'static [u8]) -> Result { + Ok(<_ as TryInto>::try_into(v)?.into()) + } +} + // TODO: Vec(ScVec), // TODO: Map(ScMap), // TODO: BigInt(ScBigInt), From a9d3fcb6a8942618387c2a4f55ef054109e765d1 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 15 Jul 2022 17:16:57 -0700 Subject: [PATCH 05/65] wip --- src/scval.rs | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/src/scval.rs b/src/scval.rs index a2569c20..ad79b7d2 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -1,5 +1,8 @@ use crate::{Hash, PublicKey, ScHash, ScObject, ScStatic, ScStatus, ScVal}; +#[cfg(not(feature = "alloc"))] +use crate::ScVec; + #[cfg(all(not(feature = "std"), feature = "alloc"))] extern crate alloc; #[cfg(all(not(feature = "std"), feature = "alloc"))] @@ -213,10 +216,87 @@ impl TryFrom<&'static [u8]> for ScVal { } } -// TODO: Vec(ScVec), +#[cfg(feature = "alloc")] +impl> TryFrom> for ScObject { + type Error = (); + fn try_from(v: Vec) -> Result { + Ok(ScObject::Vec( + v.into_iter() + .map(|t| <_ as Into>::into(t)) + .collect::>() // TODO: Impl conversion from Iterator to VecM in xdrgen generated code. + .try_into() + .map_err(|_| ())?, + )) + } +} + +#[cfg(feature = "alloc")] +impl> TryFrom> for ScVal { + type Error = (); + fn try_from(v: Vec) -> Result { + Ok(<_ as TryInto>::try_into(v)?.into()) + } +} + +#[cfg(feature = "alloc")] +impl + Clone> TryFrom<&Vec> for ScObject { + type Error = (); + fn try_from(v: &Vec) -> Result { + Ok(ScObject::Vec( + v.iter() + .map(|t| <_ as Into>::into(t.clone())) + .collect::>() // TODO: Impl conversion from Iterator to VecM in xdrgen generated code. + .try_into() + .map_err(|_| ())?, + )) + } +} + +#[cfg(feature = "alloc")] +impl<'a, T: Into> TryFrom<&'a Vec> for ScVal +where + ScObject: TryFrom<&'a Vec>, +{ + type Error = (); + fn try_from(v: &'a Vec) -> Result { + Ok(<_ as TryInto>::try_into(v) + .map_err(|_| ())? + .into()) + } +} + +#[cfg(feature = "alloc")] +impl + Clone> TryFrom<&[T]> for ScObject { + type Error = (); + fn try_from(v: &[T]) -> Result { + Ok(ScObject::Vec( + v.iter() + .map(|t| <_ as Into>::into(t.clone())) + .collect::>() // TODO: Impl conversion from Iterator to VecM in xdrgen generated code. + .try_into() + .map_err(|_| ())?, + )) + } +} + +#[cfg(feature = "alloc")] +impl<'a, T: Into> TryFrom<&'a [T]> for ScVal +where + ScObject: TryFrom<&'a [T]>, +{ + type Error = (); + fn try_from(v: &'a [T]) -> Result { + Ok(<_ as TryInto>::try_into(v) + .map_err(|_| ())? + .into()) + } +} + // TODO: Map(ScMap), // TODO: BigInt(ScBigInt), +// TODO: Reverse conversions for all types above. + impl> From> for ScVal { fn from(v: Option) -> Self { match v { From 7e7075239eeda4e361d906b5968da8edd988b9ea Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 15 Jul 2022 18:57:11 -0700 Subject: [PATCH 06/65] map --- src/scval.rs | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/scval.rs b/src/scval.rs index ad79b7d2..d914d41a 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -1,8 +1,5 @@ use crate::{Hash, PublicKey, ScHash, ScObject, ScStatic, ScStatus, ScVal}; -#[cfg(not(feature = "alloc"))] -use crate::ScVec; - #[cfg(all(not(feature = "std"), feature = "alloc"))] extern crate alloc; #[cfg(all(not(feature = "std"), feature = "alloc"))] @@ -216,6 +213,18 @@ impl TryFrom<&'static [u8]> for ScVal { } } +impl From for ScObject { + fn from(v: ScVec) -> Self { + ScObject::Vec(v) + } +} + +impl From for ScVal { + fn from(v: ScVec) -> Self { + Ok(<_ as TryInto>::into(v).into()) + } +} + #[cfg(feature = "alloc")] impl> TryFrom> for ScObject { type Error = (); @@ -292,6 +301,18 @@ where } } +impl From for ScObject { + fn from(v: ScMap) -> Self { + ScObject::Map(v) + } +} + +impl From Self { + Ok(<_ as TryInto>::into(v).into()) + } +} + // TODO: Map(ScMap), // TODO: BigInt(ScBigInt), From 9dda60c2564521ecbad723806a67406c5fe821f9 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 15 Jul 2022 18:57:30 -0700 Subject: [PATCH 07/65] mapg --- src/scval.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scval.rs b/src/scval.rs index d914d41a..62757daf 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -307,8 +307,8 @@ impl From for ScObject { } } -impl From Self { +impl From for ScVal { + fn from(v: ScMap) -> Self { Ok(<_ as TryInto>::into(v).into()) } } From 57580669d257936065145cda529e811195dff8c5 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 15 Jul 2022 21:18:33 -0700 Subject: [PATCH 08/65] fix --- src/scval.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/scval.rs b/src/scval.rs index 62757daf..1e5039e1 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -1,4 +1,4 @@ -use crate::{Hash, PublicKey, ScHash, ScObject, ScStatic, ScStatus, ScVal}; +use crate::{Hash, PublicKey, ScHash, ScMap, ScObject, ScStatic, ScStatus, ScVal, ScVec}; #[cfg(all(not(feature = "std"), feature = "alloc"))] extern crate alloc; @@ -221,7 +221,7 @@ impl From for ScObject { impl From for ScVal { fn from(v: ScVec) -> Self { - Ok(<_ as TryInto>::into(v).into()) + <_ as Into>::into(v).into() } } @@ -309,7 +309,7 @@ impl From for ScObject { impl From for ScVal { fn from(v: ScMap) -> Self { - Ok(<_ as TryInto>::into(v).into()) + <_ as Into>::into(v).into() } } From 8efa67fc8d62dde83c1d397b15bad9d9d55f2e1e Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 15 Jul 2022 23:14:40 -0700 Subject: [PATCH 09/65] numbigint --- Cargo.lock | 37 ++++++++++++++++++++++ Cargo.toml | 8 +++-- src/scval.rs | 86 +++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 124 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7c2018f9..ad46f900 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,48 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "base64" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + [[package]] name = "proc-macro2" version = "1.0.40" @@ -51,6 +87,7 @@ name = "stellar-xdr" version = "0.0.0" dependencies = [ "base64", + "num-bigint", "serde", ] diff --git a/Cargo.toml b/Cargo.toml index a3eb521a..4ed15ecf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,11 +5,13 @@ edition = "2021" [dependencies] base64 = "0.13.0" -serde = {version = "1.0.139", features = ["derive"], optional = true } +serde = { version = "1.0.139", features = ["derive"], optional = true } +num-bigint = { version = "0.4.3", optional = true } [features] default = ["std"] -std = ["alloc", "base64/std"] -serde = ["alloc", "dep:serde"] +std = ["alloc", "base64/std", "num-bigint?/std"] alloc = [] next = [] +serde = ["alloc", "dep:serde"] +num-bigint = ["alloc", "dep:num-bigint"] diff --git a/src/scval.rs b/src/scval.rs index 1e5039e1..624f176a 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -1,10 +1,13 @@ -use crate::{Hash, PublicKey, ScHash, ScMap, ScObject, ScStatic, ScStatus, ScVal, ScVec}; +use crate::{Hash, PublicKey, ScBigInt, ScHash, ScMap, ScObject, ScStatic, ScStatus, ScVal, ScVec}; #[cfg(all(not(feature = "std"), feature = "alloc"))] extern crate alloc; #[cfg(all(not(feature = "std"), feature = "alloc"))] use alloc::{string::String, vec::Vec}; +#[cfg(feature = "num-bigint")] +use num_bigint::{BigInt, Sign}; + impl From for ScVal { fn from(v: ScStatic) -> Self { Self::Static(v) @@ -313,10 +316,83 @@ impl From for ScVal { } } -// TODO: Map(ScMap), -// TODO: BigInt(ScBigInt), +// TODO: Add conversions from std::collections::HashMap, im_rcOrdMap, and other +// popular map types to ScMap. + +impl From for ScObject { + fn from(v: ScBigInt) -> Self { + ScObject::BigInt(v) + } +} + +impl From for ScVal { + fn from(v: ScBigInt) -> Self { + <_ as Into>::into(v).into() + } +} + +#[cfg(feature = "num-bigint")] +impl TryFrom for ScBigInt { + type Error = (); + fn try_from(v: BigInt) -> Result { + Ok(match v.to_bytes_be() { + (Sign::NoSign, _) => ScBigInt::Zero, + (Sign::Plus, bytes) => ScBigInt::Positive(bytes.try_into().map_err(|_| ())?), + (Sign::Minus, bytes) => ScBigInt::Negative(bytes.try_into().map_err(|_| ())?), + }) + } +} + +#[cfg(feature = "num-bigint")] +impl TryFrom for ScObject { + type Error = (); + fn try_from(v: BigInt) -> Result { + Ok(<_ as TryInto>::try_into(v)?.into()) + } +} + +#[cfg(feature = "num-bigint")] +impl TryFrom for ScVal { + type Error = (); + fn try_from(v: BigInt) -> Result { + Ok(<_ as TryInto>::try_into(v)?.into()) + } +} + +#[cfg(feature = "num-bigint")] +impl From for BigInt { + fn from(v: ScBigInt) -> Self { + match v { + ScBigInt::Zero => 0u32.into(), + ScBigInt::Positive(bytes) => BigInt::from_bytes_be(Sign::Plus, &bytes), + ScBigInt::Negative(bytes) => BigInt::from_bytes_be(Sign::Minus, &bytes), + } + } +} -// TODO: Reverse conversions for all types above. +#[cfg(feature = "num-bigint")] +impl TryFrom for BigInt { + type Error = (); + fn try_from(v: ScObject) -> Result { + if let ScObject::BigInt(b) = v { + Ok(<_ as TryInto>::try_into(b).map_err(|_| ())?) + } else { + Err(()) + } + } +} + +#[cfg(feature = "num-bigint")] +impl TryFrom for BigInt { + type Error = (); + fn try_from(v: ScVal) -> Result { + if let ScVal::Object(Some(o)) = v { + Ok(<_ as TryInto>::try_into(o).map_err(|_| ())?) + } else { + Err(()) + } + } +} impl> From> for ScVal { fn from(v: Option) -> Self { @@ -326,3 +402,5 @@ impl> From> for ScVal { } } } + +// TODO: Add reverse conversions for all types above. From d001854ac680148f1855063e5e00929267372a45 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 15 Jul 2022 23:15:14 -0700 Subject: [PATCH 10/65] comment --- Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 4ed15ecf..75769456 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,5 +13,7 @@ default = ["std"] std = ["alloc", "base64/std", "num-bigint?/std"] alloc = [] next = [] + +# Features dependent on optional dependencies. serde = ["alloc", "dep:serde"] num-bigint = ["alloc", "dep:num-bigint"] From 58dd168d1a48df30a0f33446fcb26ee0a0fe1dec Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 15 Jul 2022 23:31:28 -0700 Subject: [PATCH 11/65] tryfrom --- src/scval.rs | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/src/scval.rs b/src/scval.rs index 624f176a..b95765d5 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -316,6 +316,28 @@ impl From for ScVal { } } +impl TryFrom for ScMap { + type Error = (); + fn try_from(v: ScObject) -> Result { + if let ScObject::Map(m) = v { + Ok(m) + } else { + Err(()) + } + } +} + +impl TryFrom for ScMap { + type Error = (); + fn try_from(v: ScVal) -> Result { + if let ScVal::Object(Some(o)) = v { + <_ as TryInto>::try_into(o) + } else { + Err(()) + } + } +} + // TODO: Add conversions from std::collections::HashMap, im_rcOrdMap, and other // popular map types to ScMap. @@ -372,10 +394,10 @@ impl From for BigInt { #[cfg(feature = "num-bigint")] impl TryFrom for BigInt { - type Error = (); + type Error = >::Error; fn try_from(v: ScObject) -> Result { if let ScObject::BigInt(b) = v { - Ok(<_ as TryInto>::try_into(b).map_err(|_| ())?) + <_ as TryInto>::try_into(b) } else { Err(()) } @@ -384,10 +406,10 @@ impl TryFrom for BigInt { #[cfg(feature = "num-bigint")] impl TryFrom for BigInt { - type Error = (); + type Error = >::Error; fn try_from(v: ScVal) -> Result { if let ScVal::Object(Some(o)) = v { - Ok(<_ as TryInto>::try_into(o).map_err(|_| ())?) + <_ as TryInto>::try_into(o) } else { Err(()) } @@ -403,4 +425,15 @@ impl> From> for ScVal { } } +// TODO: Is there a way to provide this conversion without recursion? +// impl> TryFrom for Option { +// type Error = T::Error; +// fn try_from(v: ScVal) -> Result { +// match v { +// ScVal::Static(ScStatic::Void) => Ok(None), +// _ => <_ as TryFrom>::try_from(v), +// } +// } +// } + // TODO: Add reverse conversions for all types above. From 3f561122da34a9a702ac1bd92058ad7814034150 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 15 Jul 2022 23:34:55 -0700 Subject: [PATCH 12/65] fix --- src/scval.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/scval.rs b/src/scval.rs index b95765d5..7ca67974 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -394,10 +394,10 @@ impl From for BigInt { #[cfg(feature = "num-bigint")] impl TryFrom for BigInt { - type Error = >::Error; + type Error = (); fn try_from(v: ScObject) -> Result { if let ScObject::BigInt(b) = v { - <_ as TryInto>::try_into(b) + Ok(<_ as TryInto>::try_into(b).map_err(|_| ())?) } else { Err(()) } @@ -406,10 +406,10 @@ impl TryFrom for BigInt { #[cfg(feature = "num-bigint")] impl TryFrom for BigInt { - type Error = >::Error; + type Error = (); fn try_from(v: ScVal) -> Result { if let ScVal::Object(Some(o)) = v { - <_ as TryInto>::try_into(o) + Ok(<_ as TryInto>::try_into(o).map_err(|_| ())?) } else { Err(()) } From 6e85b33f18b03c3a236b7073eb9c87eb15663fd6 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 15 Jul 2022 23:37:38 -0700 Subject: [PATCH 13/65] add comments --- src/scval.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/scval.rs b/src/scval.rs index 7ca67974..9be8ba9a 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -108,6 +108,8 @@ impl From for ScVal { } } +// TODO: Reverse conditions for ScVal/etc => ScHash/Hash. + impl From for ScObject { fn from(v: PublicKey) -> Self { ScObject::PublicKey(v) @@ -120,6 +122,8 @@ impl From for ScVal { } } +// TODO: Reverse conditions for ScVal/etc => PublicKey. + #[cfg(feature = "alloc")] impl TryFrom for ScVal { type Error = (); @@ -152,6 +156,8 @@ impl TryFrom<&'static str> for ScVal { } } +// TODO: Reverse conditions for ScVal/etc => String/&str/etc. + #[cfg(feature = "alloc")] impl TryFrom> for ScObject { type Error = (); @@ -216,6 +222,8 @@ impl TryFrom<&'static [u8]> for ScVal { } } +// TODO: Reverse conditions for ScVal/etc => Binary/etc. + impl From for ScObject { fn from(v: ScVec) -> Self { ScObject::Vec(v) @@ -304,6 +312,8 @@ where } } +// TODO: Reverse conditions for ScVal/etc => Vec/etc. + impl From for ScObject { fn from(v: ScMap) -> Self { ScObject::Map(v) From 489014e94c7ca080680e296c4b73824f7ee4b1d4 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 15 Jul 2022 23:37:47 -0700 Subject: [PATCH 14/65] comments --- src/scval.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/scval.rs b/src/scval.rs index 9be8ba9a..4bd53fa7 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -445,5 +445,3 @@ impl> From> for ScVal { // } // } // } - -// TODO: Add reverse conversions for all types above. From 7cfbbfe0aa3aa1c4084ed3cbff03137357ac6a1c Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 15 Jul 2022 23:39:26 -0700 Subject: [PATCH 15/65] comments --- src/scval.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/scval.rs b/src/scval.rs index 4bd53fa7..3b6e10dc 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -14,30 +14,40 @@ impl From for ScVal { } } +// TODO: Reverse conditions for ScVal/etc => ScStatic. + impl From for ScVal { fn from(v: ScObject) -> Self { ScVal::Object(Some(v)) } } +// TODO: Reverse conditions for ScVal/etc => ScObject. + impl From for ScVal { fn from(v: ScStatus) -> Self { ScVal::Status(v) } } +// TODO: Reverse conditions for ScVal/etc => ScStatus. + impl From for ScVal { fn from(v: i32) -> ScVal { ScVal::I32(v) } } +// TODO: Reverse conditions for ScVal/etc => i32. + impl From for ScVal { fn from(v: u32) -> ScVal { ScVal::U32(v) } } +// TODO: Reverse conditions for ScVal/etc => u32. + impl From for ScVal { fn from(v: i64) -> ScVal { if v < 0 { @@ -48,36 +58,48 @@ impl From for ScVal { } } +// TODO: Reverse conditions for ScVal/etc => i64. + impl From for ScVal { fn from(v: u64) -> ScVal { ScObject::U64(v).into() } } +// TODO: Reverse conditions for ScVal/etc => u64. + impl From<()> for ScVal { fn from(_: ()) -> Self { ScStatic::Void.into() } } +// TODO: Reverse conditions for ScVal/etc => (). + impl From for ScVal { fn from(v: bool) -> Self { if v { ScStatic::True } else { ScStatic::False }.into() } } +// TODO: Reverse conditions for ScVal/etc => bool. + impl From for ScObject { fn from(v: i64) -> ScObject { ScObject::I64(v) } } +// TODO: Reverse conditions for ScVal/etc => i64. + impl From for ScObject { fn from(v: u64) -> ScObject { ScObject::U64(v) } } +// TODO: Reverse conditions for ScVal/etc => u64. + impl From for ScObject { fn from(v: ScHash) -> Self { ScObject::Hash(v) From d9c09bb6a1760d63d1d07836eb0d936787051bd6 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 15 Jul 2022 23:40:29 -0700 Subject: [PATCH 16/65] fn --- src/scval.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/scval.rs b/src/scval.rs index 3b6e10dc..0fe3ea05 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -85,15 +85,21 @@ impl From for ScVal { // TODO: Reverse conditions for ScVal/etc => bool. impl From for ScObject { - fn from(v: i64) -> ScObject { + fn from(v: i64) -> Self { ScObject::I64(v) } } +impl From for ScVal { + fn from(v: i64) -> Self { + <_ as Into>::into(v).into() + } +} + // TODO: Reverse conditions for ScVal/etc => i64. impl From for ScObject { - fn from(v: u64) -> ScObject { + fn from(v: u64) -> Self { ScObject::U64(v) } } From 56839797dbd310715fabaee288dbc3e1b9f5a412 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 15 Jul 2022 23:41:03 -0700 Subject: [PATCH 17/65] fix --- src/scval.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/scval.rs b/src/scval.rs index 0fe3ea05..db6b8a89 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -90,12 +90,6 @@ impl From for ScObject { } } -impl From for ScVal { - fn from(v: i64) -> Self { - <_ as Into>::into(v).into() - } -} - // TODO: Reverse conditions for ScVal/etc => i64. impl From for ScObject { @@ -104,6 +98,12 @@ impl From for ScObject { } } +impl From for ScVal { + fn from(v: u64) -> Self { + <_ as Into>::into(v).into() + } +} + // TODO: Reverse conditions for ScVal/etc => u64. impl From for ScObject { From e03c50ac3b95c4cd18296c9eccb315fb77b11c50 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 15 Jul 2022 23:41:28 -0700 Subject: [PATCH 18/65] dupe --- src/scval.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/scval.rs b/src/scval.rs index db6b8a89..5646bd86 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -58,14 +58,6 @@ impl From for ScVal { } } -// TODO: Reverse conditions for ScVal/etc => i64. - -impl From for ScVal { - fn from(v: u64) -> ScVal { - ScObject::U64(v).into() - } -} - // TODO: Reverse conditions for ScVal/etc => u64. impl From<()> for ScVal { From 569bb50c32b4d47b9f012b8351b9ebe807dd106c Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 15 Jul 2022 23:42:35 -0700 Subject: [PATCH 19/65] fn --- src/scval.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/scval.rs b/src/scval.rs index 5646bd86..6a8c9488 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -22,7 +22,16 @@ impl From for ScVal { } } -// TODO: Reverse conditions for ScVal/etc => ScObject. +impl TryFrom for ScObject { + type Error = (); + fn try_from(v: ScVal) -> Result { + if let ScVal::Object(Some(o)) = v { + Ok(o) + } else { + Err(()) + } + } +} impl From for ScVal { fn from(v: ScStatus) -> Self { From 57fae230091f21c0314d9c1dab2d91349d9a72f4 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 15 Jul 2022 23:43:36 -0700 Subject: [PATCH 20/65] static --- src/scval.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/scval.rs b/src/scval.rs index 6a8c9488..a605a773 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -14,7 +14,16 @@ impl From for ScVal { } } -// TODO: Reverse conditions for ScVal/etc => ScStatic. +impl TryFrom for ScStatic { + type Error = (); + fn try_from(v: ScVal) -> Result { + if let ScVal::Static(s) = v { + Ok(s) + } else { + Err(()) + } + } +} impl From for ScVal { fn from(v: ScObject) -> Self { From b491f48ed3199c0698e5e72453f6714e727ce5b3 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 15 Jul 2022 23:44:05 -0700 Subject: [PATCH 21/65] fn --- src/scval.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/scval.rs b/src/scval.rs index a605a773..4a959665 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -48,7 +48,16 @@ impl From for ScVal { } } -// TODO: Reverse conditions for ScVal/etc => ScStatus. +impl TryFrom for ScStatus { + type Error = (); + fn try_from(v: ScVal) -> Result { + if let ScVal::Status(s) = v { + Ok(s) + } else { + Err(()) + } + } +} impl From for ScVal { fn from(v: i32) -> ScVal { From 0d27b305ff9fd20e356dd4e45edda28580db5d81 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 15 Jul 2022 23:44:49 -0700 Subject: [PATCH 22/65] fn --- src/scval.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/scval.rs b/src/scval.rs index 4a959665..31b99afd 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -65,7 +65,16 @@ impl From for ScVal { } } -// TODO: Reverse conditions for ScVal/etc => i32. +impl TryFrom for i32 { + type Error = (); + fn try_from(v: ScVal) -> Result { + if let ScVal::I32(i) = v { + Ok(i) + } else { + Err(()) + } + } +} impl From for ScVal { fn from(v: u32) -> ScVal { From 8593a4500884b84efca77dcc72a8ccccfabfdab8 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Sat, 16 Jul 2022 08:25:05 -0700 Subject: [PATCH 23/65] wip --- src/scval.rs | 77 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 6 deletions(-) diff --git a/src/scval.rs b/src/scval.rs index 31b99afd..112c21fa 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -82,7 +82,16 @@ impl From for ScVal { } } -// TODO: Reverse conditions for ScVal/etc => u32. +impl TryFrom for u32 { + type Error = (); + fn try_from(v: ScVal) -> Result { + if let ScVal::U32(i) = v { + Ok(i) + } else { + Err(()) + } + } +} impl From for ScVal { fn from(v: i64) -> ScVal { @@ -94,7 +103,16 @@ impl From for ScVal { } } -// TODO: Reverse conditions for ScVal/etc => u64. +impl TryFrom for i64 { + type Error = (); + fn try_from(v: ScVal) -> Result { + if let ScVal::U63(i) | ScVal::Object(Some(ScObject::I64(i))) = v { + Ok(i) + } else { + Err(()) + } + } +} impl From<()> for ScVal { fn from(_: ()) -> Self { @@ -102,7 +120,16 @@ impl From<()> for ScVal { } } -// TODO: Reverse conditions for ScVal/etc => (). +impl TryFrom for () { + type Error = (); + fn try_from(v: ScVal) -> Result { + if let ScVal::Static(ScStatic::Void) = v { + Ok(()) + } else { + Err(()) + } + } +} impl From for ScVal { fn from(v: bool) -> Self { @@ -110,7 +137,16 @@ impl From for ScVal { } } -// TODO: Reverse conditions for ScVal/etc => bool. +impl TryFrom for bool { + type Error = (); + fn try_from(v: ScVal) -> Result { + match v { + ScVal::Static(ScStatic::False) => Ok(false), + ScVal::Static(ScStatic::True) => Ok(true), + _ => Err(()), + } + } +} impl From for ScObject { fn from(v: i64) -> Self { @@ -118,7 +154,16 @@ impl From for ScObject { } } -// TODO: Reverse conditions for ScVal/etc => i64. +impl TryFrom for i64 { + type Error = (); + fn try_from(v: ScObject) -> Result { + if let ScObject::I64(i) = v { + Ok(i) + } else { + Err(()) + } + } +} impl From for ScObject { fn from(v: u64) -> Self { @@ -132,7 +177,27 @@ impl From for ScVal { } } -// TODO: Reverse conditions for ScVal/etc => u64. +impl TryFrom for u64 { + type Error = (); + fn try_from(v: ScObject) -> Result { + if let ScObject::U64(i) = v { + Ok(i) + } else { + Err(()) + } + } +} + +impl TryFrom for u64 { + type Error = (); + fn try_from(v: ScVal) -> Result { + if let ScVal::U64() = v { + Ok(i) + } else { + Err(()) + } + } +} impl From for ScObject { fn from(v: ScHash) -> Self { From 1f2dbbabb7597ab40f19b7383b74242602c2f715 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Sat, 16 Jul 2022 08:37:28 -0700 Subject: [PATCH 24/65] fn --- src/scval.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/src/scval.rs b/src/scval.rs index 112c21fa..5cf913dd 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -191,7 +191,7 @@ impl TryFrom for u64 { impl TryFrom for u64 { type Error = (); fn try_from(v: ScVal) -> Result { - if let ScVal::U64() = v { + if let ScVal::Object(Some(ScObject::U64(i))) = v { Ok(i) } else { Err(()) @@ -229,7 +229,57 @@ impl From for ScVal { } } -// TODO: Reverse conditions for ScVal/etc => ScHash/Hash. +impl TryFrom for ScHash { + type Error = (); + fn try_from(v: ScObject) -> Result { + if let ScObject::Hash(h) = v { + Ok(h) + } else { + Err(()) + } + } +} + +impl TryFrom for ScHash { + type Error = (); + fn try_from(v: ScVal) -> Result { + if let ScVal::Object(Some(ScObject::Hash(h))) = v { + Ok(h) + } else { + Err(()) + } + } +} + +impl TryFrom for Hash { + type Error = (); + fn try_from(v: ScHash) -> Result { + let ScHash::SchashSha256(h) = v; + Ok(h) + } +} + +impl TryFrom for Hash { + type Error = (); + fn try_from(v: ScObject) -> Result { + if let ScObject::Hash(ScHash::SchashSha256(h)) = v { + Ok(h) + } else { + Err(()) + } + } +} + +impl TryFrom for Hash { + type Error = (); + fn try_from(v: ScVal) -> Result { + if let ScVal::Object(Some(ScObject::Hash(ScHash::SchashSha256(h)))) = v { + Ok(h) + } else { + Err(()) + } + } +} impl From for ScObject { fn from(v: PublicKey) -> Self { From 7605dcc0482bb8ea562a53436a24c99a50fb8ea1 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Sat, 16 Jul 2022 08:38:54 -0700 Subject: [PATCH 25/65] fn --- src/scval.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/scval.rs b/src/scval.rs index 5cf913dd..f2a3e3b1 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -293,7 +293,27 @@ impl From for ScVal { } } -// TODO: Reverse conditions for ScVal/etc => PublicKey. +impl TryFrom for PublicKey { + type Error = (); + fn try_from(v: ScObject) -> Result { + if let ScObject::PublicKey(k) = v { + Ok(k) + } else { + Err(()) + } + } +} + +impl TryFrom for PublicKey { + type Error = (); + fn try_from(v: ScVal) -> Result { + if let ScVal::Object(Some(ScObject::PublicKey(k))) = v { + Ok(k) + } else { + Err(()) + } + } +} #[cfg(feature = "alloc")] impl TryFrom for ScVal { From 16224f669fb4d1242c3ff41f6e2a7cade33d5e67 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Sat, 16 Jul 2022 08:45:01 -0700 Subject: [PATCH 26/65] fn --- src/scval.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/scval.rs b/src/scval.rs index f2a3e3b1..5ad334e9 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -8,6 +8,8 @@ use alloc::{string::String, vec::Vec}; #[cfg(feature = "num-bigint")] use num_bigint::{BigInt, Sign}; +// TODO: Add borrow conversions as well. + impl From for ScVal { fn from(v: ScStatic) -> Self { Self::Static(v) @@ -347,7 +349,19 @@ impl TryFrom<&'static str> for ScVal { } } -// TODO: Reverse conditions for ScVal/etc => String/&str/etc. +#[cfg(feature = "alloc")] +impl TryFrom for String { + type Error = (); + fn try_from(v: ScVal) -> Result { + if let ScVal::Symbol(s) = v { + // TODO: It might be worth distinguishing the error case where this + // is an invalid symbol with invalid characters. + Ok(s.into_string().map_err(|_| ())?) + } else { + Err(()) + } + } +} #[cfg(feature = "alloc")] impl TryFrom> for ScObject { From 79c6e328c44d2eecdadb06778fe5d9972c829a9d Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 09:53:41 -0700 Subject: [PATCH 27/65] wip --- src/scval.rs | 78 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 11 deletions(-) diff --git a/src/scval.rs b/src/scval.rs index 5ad334e9..eb23f0f2 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -1,4 +1,6 @@ -use crate::{Hash, PublicKey, ScBigInt, ScHash, ScMap, ScObject, ScStatic, ScStatus, ScVal, ScVec}; +use crate::{ + Hash, PublicKey, ScBigInt, ScHash, ScMap, ScObject, ScStatic, ScStatus, ScSymbol, ScVal, ScVec, +}; #[cfg(all(not(feature = "std"), feature = "alloc"))] extern crate alloc; @@ -317,6 +319,22 @@ impl TryFrom for PublicKey { } } +impl From for ScVal { + fn from(v: ScSymbol) -> Self { + ScVal::Symbol(v) + } +} + +impl TryFrom for ScSymbol { + fn from(v: ScSymbol) -> Self { + if let ScVal::Symbol(s) = v { + Ok(s) + } else { + Err(()) + } + } +} + #[cfg(feature = "alloc")] impl TryFrom for ScVal { type Error = (); @@ -363,19 +381,11 @@ impl TryFrom for String { } } -#[cfg(feature = "alloc")] -impl TryFrom> for ScObject { - type Error = (); - fn try_from(v: Vec) -> Result { - Ok(ScObject::Binary(v.try_into().map_err(|_| ())?)) - } -} - #[cfg(feature = "alloc")] impl TryFrom> for ScVal { type Error = (); fn try_from(v: Vec) -> Result { - Ok(<_ as TryInto>::try_into(v)?.into()) + Ok(<_ as TryInto>::try_into(&v)?.into()) } } @@ -427,7 +437,53 @@ impl TryFrom<&'static [u8]> for ScVal { } } -// TODO: Reverse conditions for ScVal/etc => Binary/etc. +#[cfg(feature = "alloc")] +impl TryFrom for Vec { + type Error = (); + fn try_from(v: ScObject) -> Result { + if let ScObject::Binary(b) = v { + Ok(b.into()) + } else { + Err(()) + } + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&ScObject> for Vec { + type Error = (); + fn try_from(v: &ScObject) -> Result { + if let ScObject::Binary(b) = v { + Ok(b.into()) + } else { + Err(()) + } + } +} + +#[cfg(feature = "alloc")] +impl TryFrom for Vec { + type Error = (); + fn try_from(v: ScVal) -> Result { + if let ScVal::Object(Some(ScObject::Binary(b))) = v { + Ok(b.into()) + } else { + Err(()) + } + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&ScVal> for Vec { + type Error = (); + fn try_from(v: &ScVal) -> Result { + if let ScVal::Object(Some(ScObject::Binary(b))) = v { + Ok(b.into()) + } else { + Err(()) + } + } +} impl From for ScObject { fn from(v: ScVec) -> Self { From f807c00a1b6052fdd0226cd4a9b9d605afed5b77 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 09:54:04 -0700 Subject: [PATCH 28/65] wip --- src/scval.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/scval.rs b/src/scval.rs index eb23f0f2..30a322e9 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -326,7 +326,8 @@ impl From for ScVal { } impl TryFrom for ScSymbol { - fn from(v: ScSymbol) -> Self { + type Error = (); + fn try_from(v: ScSymbol) -> Result { if let ScVal::Symbol(s) = v { Ok(s) } else { From b15dc93b65a403ed2a691f320c95447fbf3a52ee Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 09:56:10 -0700 Subject: [PATCH 29/65] wip --- src/scval.rs | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/scval.rs b/src/scval.rs index 30a322e9..e16f6166 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -1,5 +1,6 @@ use crate::{ - Hash, PublicKey, ScBigInt, ScHash, ScMap, ScObject, ScStatic, ScStatus, ScSymbol, ScVal, ScVec, + Hash, PublicKey, ScBigInt, ScBinary, ScHash, ScMap, ScObject, ScStatic, ScStatus, ScSymbol, + ScVal, ScVec, }; #[cfg(all(not(feature = "std"), feature = "alloc"))] @@ -382,6 +383,40 @@ impl TryFrom for String { } } +impl From for ScObject { + fn from(v: ScBinary) -> Self { + ScObject::Binary(v) + } +} + +impl TryFrom for ScBinary { + type Error = (); + fn try_from(v: ScBinary) -> Result { + if let ScObject::Binary(b) = v { + Ok(b) + } else { + Err(()) + } + } +} + +impl From for ScVal { + fn from(v: ScBinary) -> Self { + ScVal::Object(Some(ScObject::Binary(v))) + } +} + +impl TryFrom for ScBinary { + type Error = (); + fn try_from(v: ScBinary) -> Result { + if let ScVal::Object(Some(ScObject::Binary(b))) = v { + Ok(b) + } else { + Err(()) + } + } +} + #[cfg(feature = "alloc")] impl TryFrom> for ScVal { type Error = (); From b6f53a2e5fd1104e0877de5085dcd941808af739 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 10:45:05 -0700 Subject: [PATCH 30/65] fix --- src/scval.rs | 39 ++------------------------------------- 1 file changed, 2 insertions(+), 37 deletions(-) diff --git a/src/scval.rs b/src/scval.rs index e16f6166..86640e15 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -1,6 +1,5 @@ use crate::{ - Hash, PublicKey, ScBigInt, ScBinary, ScHash, ScMap, ScObject, ScStatic, ScStatus, ScSymbol, - ScVal, ScVec, + Hash, PublicKey, ScBigInt, ScHash, ScMap, ScObject, ScStatic, ScStatus, ScSymbol, ScVal, ScVec, }; #[cfg(all(not(feature = "std"), feature = "alloc"))] @@ -328,7 +327,7 @@ impl From for ScVal { impl TryFrom for ScSymbol { type Error = (); - fn try_from(v: ScSymbol) -> Result { + fn try_from(v: ScVal) -> Result { if let ScVal::Symbol(s) = v { Ok(s) } else { @@ -383,40 +382,6 @@ impl TryFrom for String { } } -impl From for ScObject { - fn from(v: ScBinary) -> Self { - ScObject::Binary(v) - } -} - -impl TryFrom for ScBinary { - type Error = (); - fn try_from(v: ScBinary) -> Result { - if let ScObject::Binary(b) = v { - Ok(b) - } else { - Err(()) - } - } -} - -impl From for ScVal { - fn from(v: ScBinary) -> Self { - ScVal::Object(Some(ScObject::Binary(v))) - } -} - -impl TryFrom for ScBinary { - type Error = (); - fn try_from(v: ScBinary) -> Result { - if let ScVal::Object(Some(ScObject::Binary(b))) = v { - Ok(b) - } else { - Err(()) - } - } -} - #[cfg(feature = "alloc")] impl TryFrom> for ScVal { type Error = (); From 2e16cac7a3e8d09ce4ecd4319892ce648989c474 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 12:28:43 -0700 Subject: [PATCH 31/65] reverse --- src/scval.rs | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/src/scval.rs b/src/scval.rs index 86640e15..37361c04 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -383,10 +383,10 @@ impl TryFrom for String { } #[cfg(feature = "alloc")] -impl TryFrom> for ScVal { +impl TryFrom> for ScObject { type Error = (); fn try_from(v: Vec) -> Result { - Ok(<_ as TryInto>::try_into(&v)?.into()) + Ok(ScObject::Binary(v.try_into().map_err(|_| ())?)) } } @@ -398,6 +398,14 @@ impl TryFrom<&Vec> for ScObject { } } +#[cfg(feature = "alloc")] +impl TryFrom> for ScVal { + type Error = (); + fn try_from(v: Vec) -> Result { + Ok(<_ as TryInto>::try_into(&v)?.into()) + } +} + #[cfg(feature = "alloc")] impl TryFrom<&Vec> for ScVal { type Error = (); @@ -574,7 +582,37 @@ where } } -// TODO: Reverse conditions for ScVal/etc => Vec/etc. +#[cfg(feature = "alloc")] +impl TryFrom for Vec +where + for<'a> T: TryFrom<&'a ScVal>, +{ + type Error = (); + fn try_from(v: ScObject) -> Result { + if let ScObject::Vec(v) = v { + v.iter() + .map(|t| T::try_from(t).map_err(|_| ())) + .collect::, _>>() + } else { + Err(()) + } + } +} + +#[cfg(feature = "alloc")] +impl TryFrom for Vec +where + for<'a> T: TryFrom<&'a ScVal>, +{ + type Error = (); + fn try_from(v: ScVal) -> Result { + if let ScVal::Object(Some(o)) = v { + <_ as TryInto>::try_into(o) + } else { + Err(()) + } + } +} impl From for ScObject { fn from(v: ScMap) -> Self { From 2a33abf6b9c1512701f7249c37e75007c2e55027 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 12:31:33 -0700 Subject: [PATCH 32/65] remove --- src/scval.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/scval.rs b/src/scval.rs index 37361c04..c89acf83 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -734,14 +734,3 @@ impl> From> for ScVal { } } } - -// TODO: Is there a way to provide this conversion without recursion? -// impl> TryFrom for Option { -// type Error = T::Error; -// fn try_from(v: ScVal) -> Result { -// match v { -// ScVal::Static(ScStatic::Void) => Ok(None), -// _ => <_ as TryFrom>::try_from(v), -// } -// } -// } From 9b9ba4b26c423ce9a35f06a24b998647e4ac893b Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 12:38:32 -0700 Subject: [PATCH 33/65] simplify --- src/scval.rs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/scval.rs b/src/scval.rs index c89acf83..225f895b 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -10,8 +10,6 @@ use alloc::{string::String, vec::Vec}; #[cfg(feature = "num-bigint")] use num_bigint::{BigInt, Sign}; -// TODO: Add borrow conversions as well. - impl From for ScVal { fn from(v: ScStatic) -> Self { Self::Static(v) @@ -583,15 +581,12 @@ where } #[cfg(feature = "alloc")] -impl TryFrom for Vec -where - for<'a> T: TryFrom<&'a ScVal>, -{ +impl + Clone> TryFrom for Vec { type Error = (); fn try_from(v: ScObject) -> Result { if let ScObject::Vec(v) = v { v.iter() - .map(|t| T::try_from(t).map_err(|_| ())) + .map(|t| T::try_from(t.clone()).map_err(|_| ())) .collect::, _>>() } else { Err(()) @@ -600,10 +595,7 @@ where } #[cfg(feature = "alloc")] -impl TryFrom for Vec -where - for<'a> T: TryFrom<&'a ScVal>, -{ +impl + Clone> TryFrom for Vec { type Error = (); fn try_from(v: ScVal) -> Result { if let ScVal::Object(Some(o)) = v { From 33e014381cabc9f2965ab02f28d33a9e3b507d0f Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 14:16:41 -0700 Subject: [PATCH 34/65] tests --- src/scval.rs | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/src/scval.rs b/src/scval.rs index 225f895b..219f0a84 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -67,6 +67,12 @@ impl From for ScVal { } } +impl From<&i32> for ScVal { + fn from(v: &i32) -> ScVal { + ScVal::I32(*v) + } +} + impl TryFrom for i32 { type Error = (); fn try_from(v: ScVal) -> Result { @@ -726,3 +732,79 @@ impl> From> for ScVal { } } } + +#[cfg(test)] +mod test { + use crate::{ScObject, ScVal}; + + #[test] + fn i32_pos() { + let v = 5; + let val: ScVal = v.try_into().unwrap(); + assert_eq!(val, ScVal::I32(5)); + let roundtrip: i32 = val.try_into().unwrap(); + assert_eq!(v, roundtrip); + } + + #[test] + fn i32_neg() { + let v = -5; + let val: ScVal = v.try_into().unwrap(); + assert_eq!(val, ScVal::I32(-5)); + let roundtrip: i32 = val.try_into().unwrap(); + assert_eq!(v, roundtrip); + } + + #[test] + fn u32() { + use crate::ScVal; + + let v = 5u32; + let val: ScVal = v.try_into().unwrap(); + assert_eq!(val, ScVal::U32(5)); + let roundtrip: u32 = val.try_into().unwrap(); + assert_eq!(v, roundtrip); + } + + #[test] + fn i64_pos() { + let v = 5i64; + let val: ScVal = v.try_into().unwrap(); + assert_eq!(val, ScVal::U63(5)); + let roundtrip: i64 = val.try_into().unwrap(); + assert_eq!(v, roundtrip); + } + + #[test] + fn i64_neg() { + let v = -5i64; + let val: ScVal = v.try_into().unwrap(); + assert_eq!(val, ScVal::Object(Some(ScObject::I64(-5)))); + let roundtrip: i64 = val.try_into().unwrap(); + assert_eq!(v, roundtrip); + } + + #[test] + fn u64() { + let v = 5u64; + let val: ScVal = v.try_into().unwrap(); + assert_eq!(val, ScVal::Object(Some(ScObject::U64(5)))); + let roundtrip: u64 = val.try_into().unwrap(); + assert_eq!(v, roundtrip); + } + + #[cfg(feature = "alloc")] + #[test] + fn vec() { + let v = vec![1, 2, 3, 4, 5]; + let val: ScVal = v.clone().try_into().unwrap(); + assert_eq!( + val, + ScVal::Object(Some(ScObject::Vec( + vec![1, 2, 3, 4, 5].try_into().unwrap() + ))) + ); + let roundtrip: Vec = val.try_into().unwrap(); + assert_eq!(v, roundtrip); + } +} From 1509f9890363fc74039313bc3449323f9ce19afa Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 14:34:21 -0700 Subject: [PATCH 35/65] fix test --- src/scval.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/scval.rs b/src/scval.rs index 219f0a84..25fa745e 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -796,14 +796,11 @@ mod test { #[cfg(feature = "alloc")] #[test] fn vec() { + extern crate alloc; + use alloc::vec; + use alloc::vec::Vec; let v = vec![1, 2, 3, 4, 5]; let val: ScVal = v.clone().try_into().unwrap(); - assert_eq!( - val, - ScVal::Object(Some(ScObject::Vec( - vec![1, 2, 3, 4, 5].try_into().unwrap() - ))) - ); let roundtrip: Vec = val.try_into().unwrap(); assert_eq!(v, roundtrip); } From da3bbddadd7b993640947484189d18fff75ff79b Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 14:39:59 -0700 Subject: [PATCH 36/65] fin --- src/scval.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/scval.rs b/src/scval.rs index 25fa745e..e635977a 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -16,6 +16,12 @@ impl From for ScVal { } } +impl From<&ScStatic> for ScVal { + fn from(v: &ScStatic) -> Self { + Self::Static(*v) + } +} + impl TryFrom for ScStatic { type Error = (); fn try_from(v: ScVal) -> Result { @@ -90,6 +96,12 @@ impl From for ScVal { } } +impl From<&u32> for ScVal { + fn from(v: &u32) -> ScVal { + ScVal::U32(*v) + } +} + impl TryFrom for u32 { type Error = (); fn try_from(v: ScVal) -> Result { @@ -111,6 +123,12 @@ impl From for ScVal { } } +impl From<&i64> for ScVal { + fn from(v: &i64) -> ScVal { + <_ as Into>::into(*v) + } +} + impl TryFrom for i64 { type Error = (); fn try_from(v: ScVal) -> Result { @@ -128,6 +146,12 @@ impl From<()> for ScVal { } } +impl From<&()> for ScVal { + fn from(_: &()) -> Self { + <_ as Into>::into(*v) + } +} + impl TryFrom for () { type Error = (); fn try_from(v: ScVal) -> Result { @@ -145,6 +169,12 @@ impl From for ScVal { } } +impl From<&bool> for ScVal { + fn from(v: &bool) -> Self { + <_ as Into>::into(*v) + } +} + impl TryFrom for bool { type Error = (); fn try_from(v: ScVal) -> Result { @@ -162,6 +192,12 @@ impl From for ScObject { } } +impl From<&i64> for ScObject { + fn from(v: &i64) -> Self { + ScObject::I64(*v) + } +} + impl TryFrom for i64 { type Error = (); fn try_from(v: ScObject) -> Result { @@ -179,6 +215,12 @@ impl From for ScObject { } } +impl From<&u64> for ScObject { + fn from(v: &u64) -> Self { + ScObject::U64(*v) + } +} + impl From for ScVal { fn from(v: u64) -> Self { <_ as Into>::into(v).into() From 18c6defaf6fe6658857b2f08764be8e3261aad57 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 14:40:29 -0700 Subject: [PATCH 37/65] fix --- src/scval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scval.rs b/src/scval.rs index e635977a..e1276b49 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -147,7 +147,7 @@ impl From<()> for ScVal { } impl From<&()> for ScVal { - fn from(_: &()) -> Self { + fn from(v: &()) -> Self { <_ as Into>::into(*v) } } From a59e850ed39e28b41d6d21d3bc6e762f56b4c594 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 14:41:12 -0700 Subject: [PATCH 38/65] fix --- src/scval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scval.rs b/src/scval.rs index e1276b49..02b208aa 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -148,7 +148,7 @@ impl From<()> for ScVal { impl From<&()> for ScVal { fn from(v: &()) -> Self { - <_ as Into>::into(*v) + ScStatic::Void.into() } } From dd31ba72ec808b983eb1270e4be7980173615d6b Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 14:41:22 -0700 Subject: [PATCH 39/65] fix --- src/scval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scval.rs b/src/scval.rs index 02b208aa..9ba29e45 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -147,7 +147,7 @@ impl From<()> for ScVal { } impl From<&()> for ScVal { - fn from(v: &()) -> Self { + fn from(_: &()) -> Self { ScStatic::Void.into() } } From 6394429af96556668892eca43a1aa6c4310d5950 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 14:47:27 -0700 Subject: [PATCH 40/65] add big int test --- src/scval.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/scval.rs b/src/scval.rs index 9ba29e45..1c02bcc9 100644 --- a/src/scval.rs +++ b/src/scval.rs @@ -846,4 +846,16 @@ mod test { let roundtrip: Vec = val.try_into().unwrap(); assert_eq!(v, roundtrip); } + + #[cfg(feature = "num-bigint")] + #[test] + fn bigint() { + use core::str::FromStr; + use num_bigint::BigInt; + + let v = BigInt::from_str("18446744073709551616").unwrap(); + let val: ScVal = v.clone().try_into().unwrap(); + let roundtrip: BigInt = val.try_into().unwrap(); + assert_eq!(v, roundtrip); + } } From e94658f138a25ac6403623791e9e59027af25201 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 15:14:58 -0700 Subject: [PATCH 41/65] Put base64 functionality behind feature flag --- Cargo.toml | 5 +++-- Makefile | 4 ++-- src/curr.rs | 4 ++-- src/next.rs | 4 ++-- tests/tx_prot18.rs | 4 ++-- tests/tx_small.rs | 7 +++---- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 75769456..7bbafda9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,16 +4,17 @@ version = "0.0.0" edition = "2021" [dependencies] -base64 = "0.13.0" +base64 = { version = "0.13.0", optional = true } serde = { version = "1.0.139", features = ["derive"], optional = true } num-bigint = { version = "0.4.3", optional = true } [features] default = ["std"] -std = ["alloc", "base64/std", "num-bigint?/std"] +std = ["alloc"] alloc = [] next = [] # Features dependent on optional dependencies. +base64 = ["std", "dep:base64"] serde = ["alloc", "dep:serde"] num-bigint = ["alloc", "dep:num-bigint"] diff --git a/Makefile b/Makefile index c674cb97..8d281d7c 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ src/curr.rs: $(XDR_FILES_LOCAL_CURR) > $@ docker run -i --rm -v $$PWD:/wd -w /wd ruby /bin/bash -c '\ gem install specific_install -v 0.3.7 && \ - gem specific_install https://github.com/stellar/xdrgen.git -b master && \ + gem specific_install https://github.com/leighmcculloch/stellar--xdrgen.git -b base64 && \ xdrgen --language rust --namespace curr --output src/ $^ \ ' rustfmt $@ @@ -52,7 +52,7 @@ src/next.rs: $(XDR_FILES_LOCAL_NEXT) > $@ docker run -i --rm -v $$PWD:/wd -w /wd ruby /bin/bash -c '\ gem install specific_install -v 0.3.7 && \ - gem specific_install https://github.com/stellar/xdrgen.git -b master && \ + gem specific_install https://github.com/leighmcculloch/stellar--xdrgen.git -b base64 && \ xdrgen --language rust --namespace next --output src/ $^ \ ' rustfmt $@ diff --git a/src/curr.rs b/src/curr.rs index 539002dc..5f51b0a5 100644 --- a/src/curr.rs +++ b/src/curr.rs @@ -255,7 +255,7 @@ where Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "base64")] fn from_xdr_base64(b64: String) -> Result { let mut b64_reader = Cursor::new(b64); let mut dec = base64::read::DecoderReader::new(&mut b64_reader, base64::STANDARD); @@ -276,7 +276,7 @@ pub trait WriteXdr { Ok(bytes) } - #[cfg(feature = "std")] + #[cfg(feature = "base64")] fn to_xdr_base64(&self) -> Result { let mut enc = base64::write::EncoderStringWriter::new(base64::STANDARD); self.write_xdr(&mut enc)?; diff --git a/src/next.rs b/src/next.rs index ed5e01cf..c48e1c8f 100644 --- a/src/next.rs +++ b/src/next.rs @@ -270,7 +270,7 @@ where Ok(t) } - #[cfg(feature = "std")] + #[cfg(feature = "base64")] fn from_xdr_base64(b64: String) -> Result { let mut b64_reader = Cursor::new(b64); let mut dec = base64::read::DecoderReader::new(&mut b64_reader, base64::STANDARD); @@ -291,7 +291,7 @@ pub trait WriteXdr { Ok(bytes) } - #[cfg(feature = "std")] + #[cfg(feature = "base64")] fn to_xdr_base64(&self) -> Result { let mut enc = base64::write::EncoderStringWriter::new(base64::STANDARD); self.write_xdr(&mut enc)?; diff --git a/tests/tx_prot18.rs b/tests/tx_prot18.rs index e61652c6..8ba34d05 100644 --- a/tests/tx_prot18.rs +++ b/tests/tx_prot18.rs @@ -1,7 +1,7 @@ -#[cfg(feature = "std")] +#![cfg(all(feature = "std", feature = "base64"))] + use stellar_xdr::{Error, OperationBody, ReadXdr, SequenceNumber, TransactionEnvelope}; -#[cfg(feature = "std")] #[test] fn test_parse_pubnet_v18_tx() -> Result<(), Error> { let xdr = "AAAAAgAAAAA/ESDPPSBIB8pWPGt/zZ3dSJhShRxziDdkmLQXrdytCQAPQkAACMblAAAABQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAABB90WssODNIgi6BHveqzxTRmIpvAFRyVNM+Hm2GVuCcAAAAAAAAAAAtDSg//ZfvJXgv2/0yiA7QUDWdXpKYhdjYEWkN4yVm+AAAABdIdugAAAAAAAAAAAKt3K0JAAAAQC3/n83fG/BCSRaIQjuqL2i1koiCHChxt1aagXn2ABCRP9IL83u5zldxuUaDBklKOHEdy4cOvl2BhPNbjs7w0QSGVuCcAAAAQKxHSgHZgZY7AMlPumIt0iZvtkbsRAtt6BYahJdnxrqm3+JuCVv/1ijWi1kM85uLfo7NAITi1TbdLg0gVFO16wM="; diff --git a/tests/tx_small.rs b/tests/tx_small.rs index 51fe0dfd..19ad717c 100644 --- a/tests/tx_small.rs +++ b/tests/tx_small.rs @@ -3,12 +3,11 @@ use stellar_xdr::{ TransactionExt, TransactionV1Envelope, Uint256, }; -#[cfg(feature = "std")] -use stellar_xdr::WriteXdr; - -#[cfg(feature = "std")] +#[cfg(all(feature = "std", feature = "base64"))] #[test] fn test_build_small_tx_with_std() -> Result<(), Error> { + use stellar_xdr::WriteXdr; + let te = TransactionEnvelope::Tx(TransactionV1Envelope { tx: Transaction { source_account: MuxedAccount::Ed25519(Uint256([0; 32])), From c4c68707c626cd019648699cca250c82333a4d6e Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 15:45:42 -0700 Subject: [PATCH 42/65] wip --- src/lib.rs | 5 +++-- src/{scval.rs => scval_conversions.rs} | 0 src/scval_validations.rs | 14 ++++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) rename src/{scval.rs => scval_conversions.rs} (100%) create mode 100644 src/scval_validations.rs diff --git a/src/lib.rs b/src/lib.rs index c44dc6b4..d27f4adb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ #[cfg(not(feature = "next"))] mod curr; +mod scval_validations; #[cfg(not(feature = "next"))] pub use curr::*; @@ -12,6 +13,6 @@ mod next; pub use next::*; #[cfg(feature = "next")] -mod scval; +mod scval_conversions; #[cfg(feature = "next")] -pub use scval::*; +pub use scval_conversions::*; diff --git a/src/scval.rs b/src/scval_conversions.rs similarity index 100% rename from src/scval.rs rename to src/scval_conversions.rs diff --git a/src/scval_validations.rs b/src/scval_validations.rs new file mode 100644 index 00000000..dc6ad298 --- /dev/null +++ b/src/scval_validations.rs @@ -0,0 +1,14 @@ +use crate::ScVal; + +pub trait Validate { + type Error; + fn validate() -> Result<(), Self::Error>; +} + +impl Validate for ScVal { + type Error = (); + + fn validate() -> Result<(), Self::Error> { + todo!() + } +} From 9d91047415c8c33eca078b4c50b40538b8f51c14 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 16:22:50 -0700 Subject: [PATCH 43/65] add some validations --- src/lib.rs | 6 +++++- src/scval_validations.rs | 36 +++++++++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d27f4adb..b293c51c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,6 @@ #[cfg(not(feature = "next"))] mod curr; -mod scval_validations; #[cfg(not(feature = "next"))] pub use curr::*; @@ -16,3 +15,8 @@ pub use next::*; mod scval_conversions; #[cfg(feature = "next")] pub use scval_conversions::*; + +#[cfg(feature = "next")] +mod scval_validations; +#[cfg(feature = "next")] +pub use scval_validations::*; diff --git a/src/scval_validations.rs b/src/scval_validations.rs index dc6ad298..325478ab 100644 --- a/src/scval_validations.rs +++ b/src/scval_validations.rs @@ -2,13 +2,43 @@ use crate::ScVal; pub trait Validate { type Error; - fn validate() -> Result<(), Self::Error>; + fn validate(&self) -> Result<(), Self::Error>; } impl Validate for ScVal { type Error = (); - fn validate() -> Result<(), Self::Error> { - todo!() + fn validate(&self) -> Result<(), Self::Error> { + // u63, bitset, symbol, obj has to be some, ScMap + match self { + ScVal::U63(i) => { + if *i >= 0 { + Ok(()) + } else { + Err(()) + } + } + ScVal::Symbol(s) => { + // Symbol is defined as valid per https://github.com/stellar/rs-stellar-contract-env/blob/94c1717516c8fad4ad65caa148183b9fcbc408db/stellar-contract-env-common/src/symbol.rs#L107-L111. + if s.iter() + .all(|c| matches!(*c as char, '_' | '0'..='9' | 'A'..='Z' | 'a'..='z')) + { + Ok(()) + } else { + Err(()) + } + } + ScVal::Bitset(b) => { + // Bitset is defined as valid per https://github.com/stellar/rs-stellar-contract-env/blob/94c1717516c8fad4ad65caa148183b9fcbc408db/stellar-contract-env-common/src/bitset.rs#L53-L60. + if b & 0x0fff_ffff_ffff_ffff == b { + Ok(()) + } else { + Err(()) + } + } + ScVal::Object(_) => todo!(), + // Other variants are always valid. + ScVal::U32(_) | ScVal::I32(_) | ScVal::Static(_) | ScVal::Status(_) => Ok(()), + } } } From ed0e05c4e9b9025eba568791a18c086cc4562a24 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 16:28:11 -0700 Subject: [PATCH 44/65] fix --- src/scval_validations.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scval_validations.rs b/src/scval_validations.rs index 325478ab..c616c7aa 100644 --- a/src/scval_validations.rs +++ b/src/scval_validations.rs @@ -30,7 +30,7 @@ impl Validate for ScVal { } ScVal::Bitset(b) => { // Bitset is defined as valid per https://github.com/stellar/rs-stellar-contract-env/blob/94c1717516c8fad4ad65caa148183b9fcbc408db/stellar-contract-env-common/src/bitset.rs#L53-L60. - if b & 0x0fff_ffff_ffff_ffff == b { + if b & 0x0fff_ffff_ffff_ffff == *b { Ok(()) } else { Err(()) From 0390aed46b76d6e96cb218c0b8de008ce8e4cbb0 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 16:42:48 -0700 Subject: [PATCH 45/65] basics --- src/scval_validations.rs | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/scval_validations.rs b/src/scval_validations.rs index c616c7aa..23dc8b88 100644 --- a/src/scval_validations.rs +++ b/src/scval_validations.rs @@ -1,10 +1,19 @@ -use crate::ScVal; +use crate::{ScMap, ScObject, ScVal}; pub trait Validate { type Error; fn validate(&self) -> Result<(), Self::Error>; } +impl Validate for ScMap { + type Error = (); + + fn validate(&self) -> Result<(), Self::Error> { + // TODO: Validate that the map is sorted and has no duplicates, or find a way to guarantee this to be the case. + todo!() + } +} + impl Validate for ScVal { type Error = (); @@ -12,12 +21,14 @@ impl Validate for ScVal { // u63, bitset, symbol, obj has to be some, ScMap match self { ScVal::U63(i) => { + // U63 is defined as valid per https://github.com/stellar/stellar-protocol/blob/master/core/cap-0046.md#host-value-type. if *i >= 0 { Ok(()) } else { Err(()) } } + ScVal::Symbol(s) => { // Symbol is defined as valid per https://github.com/stellar/rs-stellar-contract-env/blob/94c1717516c8fad4ad65caa148183b9fcbc408db/stellar-contract-env-common/src/symbol.rs#L107-L111. if s.iter() @@ -28,6 +39,7 @@ impl Validate for ScVal { Err(()) } } + ScVal::Bitset(b) => { // Bitset is defined as valid per https://github.com/stellar/rs-stellar-contract-env/blob/94c1717516c8fad4ad65caa148183b9fcbc408db/stellar-contract-env-common/src/bitset.rs#L53-L60. if b & 0x0fff_ffff_ffff_ffff == *b { @@ -36,8 +48,24 @@ impl Validate for ScVal { Err(()) } } - ScVal::Object(_) => todo!(), - // Other variants are always valid. + + ScVal::Object(None) => Err(()), + + ScVal::Object(Some(o)) => match o { + ScObject::Map(m) => m.validate(), + + // Other variants of ScObject are always valid. + ScObject::Vec(_) + | ScObject::U64(_) + | ScObject::I64(_) + | ScObject::I64(_) + | ScObject::Binary(_) + | ScObject::BigInt(_) + | ScObject::Hash(_) + | ScObject::PublicKey(_) => Ok(()), + }, + + // Other variants of ScVal are always valid. ScVal::U32(_) | ScVal::I32(_) | ScVal::Static(_) | ScVal::Status(_) => Ok(()), } } From f070022c2726b32629fd5a26b03725197d3f6411 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 16:56:52 -0700 Subject: [PATCH 46/65] tests --- src/scval_validations.rs | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/scval_validations.rs b/src/scval_validations.rs index 23dc8b88..774b0b85 100644 --- a/src/scval_validations.rs +++ b/src/scval_validations.rs @@ -58,7 +58,6 @@ impl Validate for ScVal { ScObject::Vec(_) | ScObject::U64(_) | ScObject::I64(_) - | ScObject::I64(_) | ScObject::Binary(_) | ScObject::BigInt(_) | ScObject::Hash(_) @@ -70,3 +69,31 @@ impl Validate for ScVal { } } } + +#[cfg(test)] +mod test { + use crate::{ScVal, Validate}; + + #[test] + fn u63() { + assert_eq!(ScVal::U63(0).validate(), Ok(())); + assert_eq!(ScVal::U63(1).validate(), Ok(())); + assert_eq!(ScVal::U63(i64::MAX).validate(), Ok(())); + assert_eq!(ScVal::U63(-1).validate(), Err(())); + } + + #[test] + fn symbol() { + assert_eq!(ScVal::Symbol("".try_into().unwrap()).validate(), Ok(())); + assert_eq!(ScVal::Symbol("a0A_".try_into().unwrap()).validate(), Ok(())); + assert_eq!(ScVal::Symbol("]".try_into().unwrap()).validate(), Err(())); + } + + #[test] + fn bitset() { + assert_eq!(ScVal::Bitset(0x0000_0000_0000_0000).validate(), Ok(())); + assert_eq!(ScVal::Bitset(0x0fff_ffff_ffff_ffff).validate(), Ok(())); + assert_eq!(ScVal::Bitset(0x1000_0000_0000_0000).validate(), Err(())); + assert_eq!(ScVal::Bitset(0x1fff_ffff_ffff_ffff).validate(), Err(())); + } +} From 1f214e194b6090dd99bf1dcf4cb8ed06fc69ec6b Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 17:55:49 -0700 Subject: [PATCH 47/65] add mapg --- src/scval_validations.rs | 83 +++++++++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 10 deletions(-) diff --git a/src/scval_validations.rs b/src/scval_validations.rs index 774b0b85..e709dee9 100644 --- a/src/scval_validations.rs +++ b/src/scval_validations.rs @@ -5,15 +5,6 @@ pub trait Validate { fn validate(&self) -> Result<(), Self::Error>; } -impl Validate for ScMap { - type Error = (); - - fn validate(&self) -> Result<(), Self::Error> { - // TODO: Validate that the map is sorted and has no duplicates, or find a way to guarantee this to be the case. - todo!() - } -} - impl Validate for ScVal { type Error = (); @@ -70,9 +61,23 @@ impl Validate for ScVal { } } +impl Validate for ScMap { + type Error = (); + + fn validate(&self) -> Result<(), Self::Error> { + // Check the map is sorted by key, and there are no keys that are + // duplicates. + if self.windows(2).all(|w| w[0].key < w[1].key) { + Ok(()) + } else { + Err(()) + } + } +} + #[cfg(test)] mod test { - use crate::{ScVal, Validate}; + use crate::{ScMap, ScMapEntry, ScObject, ScVal, Validate}; #[test] fn u63() { @@ -96,4 +101,62 @@ mod test { assert_eq!(ScVal::Bitset(0x1000_0000_0000_0000).validate(), Err(())); assert_eq!(ScVal::Bitset(0x1fff_ffff_ffff_ffff).validate(), Err(())); } + + #[test] + fn map() { + assert_eq!( + ScVal::Object(Some(ScObject::Map(ScMap( + vec![ + ScMapEntry { + key: ScVal::U63(0), + val: ScVal::U63(1), + }, + ScMapEntry { + key: ScVal::U63(1), + val: ScVal::U63(1), + } + ] + .try_into() + .unwrap() + )))) + .validate(), + Ok(()) + ); + assert_eq!( + ScVal::Object(Some(ScObject::Map(ScMap( + vec![ + ScMapEntry { + key: ScVal::U63(2), + val: ScVal::U63(1), + }, + ScMapEntry { + key: ScVal::U63(1), + val: ScVal::U63(1), + } + ] + .try_into() + .unwrap() + )))) + .validate(), + Err(()) + ); + assert_eq!( + ScVal::Object(Some(ScObject::Map(ScMap( + vec![ + ScMapEntry { + key: ScVal::U32(1), + val: ScVal::U63(1), + }, + ScMapEntry { + key: ScVal::U63(2), + val: ScVal::U63(1), + }, + ] + .try_into() + .unwrap() + )))) + .validate(), + Err(()) + ); + } } From 32ff6bc2f527943d18ff0c896b6a2bdfb7afa722 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 17:57:05 -0700 Subject: [PATCH 48/65] add todo --- src/scval_validations.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/scval_validations.rs b/src/scval_validations.rs index e709dee9..bca6047c 100644 --- a/src/scval_validations.rs +++ b/src/scval_validations.rs @@ -65,6 +65,9 @@ impl Validate for ScMap { type Error = (); fn validate(&self) -> Result<(), Self::Error> { + // TODO: Is this sufficient? Is this sufficient for all future variants + // of ScVal? Should instead we serialize keys to XDR bytes and compare + // those? // Check the map is sorted by key, and there are no keys that are // duplicates. if self.windows(2).all(|w| w[0].key < w[1].key) { From def358460fe48ed344709812864b364d24314ec4 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 17:57:37 -0700 Subject: [PATCH 49/65] regen --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 8d281d7c..c674cb97 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ src/curr.rs: $(XDR_FILES_LOCAL_CURR) > $@ docker run -i --rm -v $$PWD:/wd -w /wd ruby /bin/bash -c '\ gem install specific_install -v 0.3.7 && \ - gem specific_install https://github.com/leighmcculloch/stellar--xdrgen.git -b base64 && \ + gem specific_install https://github.com/stellar/xdrgen.git -b master && \ xdrgen --language rust --namespace curr --output src/ $^ \ ' rustfmt $@ @@ -52,7 +52,7 @@ src/next.rs: $(XDR_FILES_LOCAL_NEXT) > $@ docker run -i --rm -v $$PWD:/wd -w /wd ruby /bin/bash -c '\ gem install specific_install -v 0.3.7 && \ - gem specific_install https://github.com/leighmcculloch/stellar--xdrgen.git -b base64 && \ + gem specific_install https://github.com/stellar/xdrgen.git -b master && \ xdrgen --language rust --namespace next --output src/ $^ \ ' rustfmt $@ From 60b9528f37694ec1d3e829d8252eea79e36a68c4 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 18:05:14 -0700 Subject: [PATCH 50/65] add missing errors doc --- src/scval_validations.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/scval_validations.rs b/src/scval_validations.rs index 774b0b85..ce1cfa14 100644 --- a/src/scval_validations.rs +++ b/src/scval_validations.rs @@ -1,3 +1,5 @@ +#![allow(clippy::missing_errors_doc)] + use crate::{ScMap, ScObject, ScVal}; pub trait Validate { From b2d882ff26bd298051eddd97dc170ed12b9774ee Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 18:06:15 -0700 Subject: [PATCH 51/65] move --- src/scval_validations.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/scval_validations.rs b/src/scval_validations.rs index ce1cfa14..237c4c7f 100644 --- a/src/scval_validations.rs +++ b/src/scval_validations.rs @@ -7,15 +7,6 @@ pub trait Validate { fn validate(&self) -> Result<(), Self::Error>; } -impl Validate for ScMap { - type Error = (); - - fn validate(&self) -> Result<(), Self::Error> { - // TODO: Validate that the map is sorted and has no duplicates, or find a way to guarantee this to be the case. - todo!() - } -} - impl Validate for ScVal { type Error = (); @@ -72,6 +63,15 @@ impl Validate for ScVal { } } +impl Validate for ScMap { + type Error = (); + + fn validate(&self) -> Result<(), Self::Error> { + // TODO: Validate that the map is sorted and has no duplicates, or find a way to guarantee this to be the case. + todo!() + } +} + #[cfg(test)] mod test { use crate::{ScVal, Validate}; From 0c0aaa405b2594f504e8da4c47106c24c39212e3 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 18:18:13 -0700 Subject: [PATCH 52/65] fix --- src/scval_validations.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/scval_validations.rs b/src/scval_validations.rs index a67cd6d9..7995f85a 100644 --- a/src/scval_validations.rs +++ b/src/scval_validations.rs @@ -82,7 +82,9 @@ impl Validate for ScMap { #[cfg(test)] mod test { + extern crate alloc; use crate::{ScMap, ScMapEntry, ScObject, ScVal, Validate}; + use alloc::vec; #[test] fn u63() { From 896fc2afae07881239ada44844cffb468e11116e Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 18:39:15 -0700 Subject: [PATCH 53/65] add todo --- src/scval_validations.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/scval_validations.rs b/src/scval_validations.rs index 237c4c7f..2827efad 100644 --- a/src/scval_validations.rs +++ b/src/scval_validations.rs @@ -14,7 +14,7 @@ impl Validate for ScVal { // u63, bitset, symbol, obj has to be some, ScMap match self { ScVal::U63(i) => { - // U63 is defined as valid per https://github.com/stellar/stellar-protocol/blob/master/core/cap-0046.md#host-value-type. + // U63 is defined as valid per https://stellar.org/protocol/cap-46#comparison. if *i >= 0 { Ok(()) } else { @@ -76,6 +76,9 @@ impl Validate for ScMap { mod test { use crate::{ScVal, Validate}; + // TODO: Write tests to validate the statements in CAP-46. + // https://stellar.org/protocol/cap-46#comparison + #[test] fn u63() { assert_eq!(ScVal::U63(0).validate(), Ok(())); From 4e4ba8ef76356c89c645ac1a26c83628091913d0 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 20:42:51 -0700 Subject: [PATCH 54/65] remove comment --- src/scval_validations.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/scval_validations.rs b/src/scval_validations.rs index 2827efad..2a9c57dd 100644 --- a/src/scval_validations.rs +++ b/src/scval_validations.rs @@ -76,9 +76,6 @@ impl Validate for ScMap { mod test { use crate::{ScVal, Validate}; - // TODO: Write tests to validate the statements in CAP-46. - // https://stellar.org/protocol/cap-46#comparison - #[test] fn u63() { assert_eq!(ScVal::U63(0).validate(), Ok(())); From dfe469e4957766052094f0d8ec04bc8c2ded60c8 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 18 Jul 2022 20:47:01 -0700 Subject: [PATCH 55/65] wip --- src/scval_validations.rs | 53 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/scval_validations.rs b/src/scval_validations.rs index e5c20804..a168c305 100644 --- a/src/scval_validations.rs +++ b/src/scval_validations.rs @@ -111,6 +111,59 @@ mod test { #[test] fn map() { + // Values and objects in the data model have a total order. When + // comparing two values A and B: + // - If A is a positive int64 and B is not, A is less than B. + assert_eq!( + ScVal::Object(Some(ScObject::Map(ScMap( + vec![ + ScMapEntry { + key: ScVal::U63(0), + val: ScVal::U32(1), + }, + ScMapEntry { + key: ScVal::U63(1), + val: ScVal::U63(1), + } + ] + .try_into() + .unwrap() + )))) + .validate(), + Ok(()) + ); + // - If A and B are both positive int64 values, they are ordered by the + // normal int64 order. + // - If A and B are both tagged and if A has a lesser tag than B, A is + // less than B. + // - If A and B are both equally tagged, then: + // - If they have tag 0, they are ordered by the normal uint32 order + // on their low 32 bits. + // - If they have tag 1, they are ordered by the normal int32 order + // on their low 32 bits. + // - If they have tag 2, 5 or 6 or 7 they are ordered by the normal + // uint64 order on the zero-extension of their low 60 bits. + // - If they have tag 4 they are ordered by the lexicographical order + // of their Unicode string value. + // - If they have tag 3 they are ordered by calling obj_cmp(A, B) + // which performs deep object comparison. + // + // Deep object comparison can be accessed by either guest or host: it is + // provided to guests as a host function via the host environment + // interface. It performs a recursive structural comparison of objects + // and values embedded in objects using the following rules: + // - If A and B have different object types, they are ordered by object + // type code. + // - If A and B are boxes, their values are ordered by the value rules + // above. + // - If A and B are vectors, they are ordered by lexicographic + // extension of the value order + // - If A and B are maps, they are ordered lexicographically as ordered + // vectors of (key, value) pairs + // - If A and B are int64 or uint64, they are ordered using the normal + // order for those types + // - If A and B are binary, they are ordered using the lexicograhical + // order of their respective bytes assert_eq!( ScVal::Object(Some(ScObject::Map(ScMap( vec![ From 0ed963361a2f3978017eb781d6d7746fb937bf7a Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Tue, 19 Jul 2022 13:02:27 -0700 Subject: [PATCH 56/65] Add helper for sorted maps, trim comments in validate. --- src/lib.rs | 5 +++ src/scmap.rs | 68 ++++++++++++++++++++++++++++++++++++++++ src/scval_validations.rs | 44 ++++---------------------- 3 files changed, 79 insertions(+), 38 deletions(-) create mode 100644 src/scmap.rs diff --git a/src/lib.rs b/src/lib.rs index b293c51c..9e41bd8b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,3 +20,8 @@ pub use scval_conversions::*; mod scval_validations; #[cfg(feature = "next")] pub use scval_validations::*; + +#[cfg(all(feature = "alloc", feature = "next"))] +mod scmap; +#[cfg(all(feature = "alloc", feature = "next"))] +pub use scmap::*; diff --git a/src/scmap.rs b/src/scmap.rs new file mode 100644 index 00000000..023c4117 --- /dev/null +++ b/src/scmap.rs @@ -0,0 +1,68 @@ +#![allow(clippy::result_unit_err)] +#![allow(clippy::missing_errors_doc)] + +use crate::{ScMap, ScMapEntry, ScVal, Validate}; +extern crate alloc; +use alloc::vec::Vec; + +impl ScMap { + pub fn sorted_from_entries>(entries: I) -> Result { + let mut v: Vec = entries.collect(); + v.sort_by(|a, b| a.key.cmp(&b.key)); + let m = ScMap(v.try_into()?); + // `validate` here will further check that there are no duplicates. + m.validate()?; + Ok(m) + } + + pub fn sorted_from_pairs>(pairs: I) -> Result + where + ScVal: From + From, + { + Self::sorted_from_entries(pairs.map(|(key, val)| ScMapEntry { + key: key.into(), + val: val.into(), + })) + } + + pub fn sorted_from>(src: II) -> Result + where + ScVal: From + From, + { + Self::sorted_from_pairs(src.into_iter()) + } +} + +#[cfg(test)] +mod test { + use super::*; + use alloc::{collections::BTreeMap, vec}; + + #[test] + fn scmap_from_map() -> Result<(), ()> { + let mut m: BTreeMap = BTreeMap::new(); + m.insert(1, 2); + m.insert(5, 6); + m.insert(3, 4); + let scm = ScMap::sorted_from(m)?; + assert_eq!(scm.0.first().unwrap().key, 1u32.into()); + assert_eq!(scm.0.last().unwrap().key, 5u32.into()); + Ok(()) + } + + #[test] + fn scmap_from_pairs() -> Result<(), ()> { + let pairs: Vec<(u32, u32)> = vec![(3, 4), (5, 6), (1, 2)]; + let scm = ScMap::sorted_from(pairs)?; + assert_eq!(scm.0.first().unwrap().key, 1u32.into()); + assert_eq!(scm.0.last().unwrap().key, 5u32.into()); + Ok(()) + } + + #[test] + fn scmap_from_bad_pairs() { + let pairs: Vec<(u32, u32)> = vec![(3, 4), (3, 5), (5, 6), (1, 2)]; + let scm = ScMap::sorted_from(pairs); + assert!(scm.is_err()); + } +} diff --git a/src/scval_validations.rs b/src/scval_validations.rs index 268201f8..ccc0d2c7 100644 --- a/src/scval_validations.rs +++ b/src/scval_validations.rs @@ -66,9 +66,6 @@ impl Validate for ScMap { type Error = (); fn validate(&self) -> Result<(), Self::Error> { - // TODO: Is this sufficient? Is this sufficient for all future variants - // of ScVal? Should instead we serialize keys to XDR bytes and compare - // those? // Check the map is sorted by key, and there are no keys that are // duplicates. if self.windows(2).all(|w| w[0].key < w[1].key) { @@ -107,10 +104,13 @@ mod test { } #[test] + #[cfg(feature = "alloc")] fn map() { - // Values and objects in the data model have a total order. When - // comparing two values A and B: - // - If A is a positive int64 and B is not, A is less than B. + extern crate alloc; + use crate::{ScMap, ScMapEntry, ScObject}; + use alloc::vec; + // Maps should be sorted by key and have no duplicates. The sort order + // is just the "normal" sort order on ScVal emitted by derive(PartialOrd). assert_eq!( ScVal::Object(Some(ScObject::Map(ScMap( vec![ @@ -129,38 +129,6 @@ mod test { .validate(), Ok(()) ); - // - If A and B are both positive int64 values, they are ordered by the - // normal int64 order. - // - If A and B are both tagged and if A has a lesser tag than B, A is - // less than B. - // - If A and B are both equally tagged, then: - // - If they have tag 0, they are ordered by the normal uint32 order - // on their low 32 bits. - // - If they have tag 1, they are ordered by the normal int32 order - // on their low 32 bits. - // - If they have tag 2, 5 or 6 or 7 they are ordered by the normal - // uint64 order on the zero-extension of their low 60 bits. - // - If they have tag 4 they are ordered by the lexicographical order - // of their Unicode string value. - // - If they have tag 3 they are ordered by calling obj_cmp(A, B) - // which performs deep object comparison. - // - // Deep object comparison can be accessed by either guest or host: it is - // provided to guests as a host function via the host environment - // interface. It performs a recursive structural comparison of objects - // and values embedded in objects using the following rules: - // - If A and B have different object types, they are ordered by object - // type code. - // - If A and B are boxes, their values are ordered by the value rules - // above. - // - If A and B are vectors, they are ordered by lexicographic - // extension of the value order - // - If A and B are maps, they are ordered lexicographically as ordered - // vectors of (key, value) pairs - // - If A and B are int64 or uint64, they are ordered using the normal - // order for those types - // - If A and B are binary, they are ordered using the lexicograhical - // order of their respective bytes assert_eq!( ScVal::Object(Some(ScObject::Map(ScMap( vec![ From 3b63c8a47f9285019948707920c51d418b77f055 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Tue, 19 Jul 2022 19:12:23 -0700 Subject: [PATCH 57/65] change test name --- src/scmap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scmap.rs b/src/scmap.rs index 023c4117..ba7462b4 100644 --- a/src/scmap.rs +++ b/src/scmap.rs @@ -60,7 +60,7 @@ mod test { } #[test] - fn scmap_from_bad_pairs() { + fn scmap_from_pairs_containing_duplicate_keys() { let pairs: Vec<(u32, u32)> = vec![(3, 4), (3, 5), (5, 6), (1, 2)]; let scm = ScMap::sorted_from(pairs); assert!(scm.is_err()); From 986e1e6fd015f148654df9194a9e9b65ea2f3e77 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Tue, 19 Jul 2022 19:13:17 -0700 Subject: [PATCH 58/65] add comment --- src/scmap.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/scmap.rs b/src/scmap.rs index ba7462b4..5c56add5 100644 --- a/src/scmap.rs +++ b/src/scmap.rs @@ -8,6 +8,7 @@ use alloc::vec::Vec; impl ScMap { pub fn sorted_from_entries>(entries: I) -> Result { let mut v: Vec = entries.collect(); + // TODO: Add tests that prove order consistency of ScVal with RawVal. https://github.com/stellar/rs-stellar-xdr/issues/117 v.sort_by(|a, b| a.key.cmp(&b.key)); let m = ScMap(v.try_into()?); // `validate` here will further check that there are no duplicates. From 06260039ba94e8e41139ca94d8eb599011bf266a Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Wed, 20 Jul 2022 11:00:05 -0700 Subject: [PATCH 59/65] Switch from From to Into --- src/scmap.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/scmap.rs b/src/scmap.rs index 5c56add5..c96f75b2 100644 --- a/src/scmap.rs +++ b/src/scmap.rs @@ -6,7 +6,10 @@ extern crate alloc; use alloc::vec::Vec; impl ScMap { - pub fn sorted_from_entries>(entries: I) -> Result { + pub fn sorted_from_entries(entries: I) -> Result + where + I: Iterator, + { let mut v: Vec = entries.collect(); // TODO: Add tests that prove order consistency of ScVal with RawVal. https://github.com/stellar/rs-stellar-xdr/issues/117 v.sort_by(|a, b| a.key.cmp(&b.key)); @@ -16,9 +19,11 @@ impl ScMap { Ok(m) } - pub fn sorted_from_pairs>(pairs: I) -> Result + pub fn sorted_from_pairs(pairs: I) -> Result where - ScVal: From + From, + K: Into, + V: Into, + I: Iterator, { Self::sorted_from_entries(pairs.map(|(key, val)| ScMapEntry { key: key.into(), @@ -26,9 +31,11 @@ impl ScMap { })) } - pub fn sorted_from>(src: II) -> Result + pub fn sorted_from(src: I) -> Result where - ScVal: From + From, + K: Into, + V: Into, + I: IntoIterator, { Self::sorted_from_pairs(src.into_iter()) } From f197cbe7ae4835b716cf2e097a34e6d7a403f8c5 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Wed, 20 Jul 2022 15:58:24 -0700 Subject: [PATCH 60/65] comment --- src/scmap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scmap.rs b/src/scmap.rs index c96f75b2..6acc36b8 100644 --- a/src/scmap.rs +++ b/src/scmap.rs @@ -14,7 +14,7 @@ impl ScMap { // TODO: Add tests that prove order consistency of ScVal with RawVal. https://github.com/stellar/rs-stellar-xdr/issues/117 v.sort_by(|a, b| a.key.cmp(&b.key)); let m = ScMap(v.try_into()?); - // `validate` here will further check that there are no duplicates. + // `validate` will further check that there are no duplicates. m.validate()?; Ok(m) } From 529a57a5132bad12eb371a027ad2bf8e49d0bc73 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Wed, 20 Jul 2022 16:46:32 -0700 Subject: [PATCH 61/65] add error type --- src/curr.rs | 20 ++++++++++++++++++++ src/next.rs | 20 ++++++++++++++++++++ src/scmap.rs | 9 ++++----- src/scval_validations.rs | 30 +++++++++++++++--------------- 4 files changed, 59 insertions(+), 20 deletions(-) diff --git a/src/curr.rs b/src/curr.rs index 5f51b0a5..79c74694 100644 --- a/src/curr.rs +++ b/src/curr.rs @@ -76,6 +76,9 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; +/// Error contains all errors returned by functions in this crate. It can be +/// compared via `PartialEq`, however any contained IO errors will only be +/// compared on their `ErrorKind`. #[derive(Debug)] pub enum Error { Invalid, @@ -87,6 +90,23 @@ pub enum Error { Io(io::Error), } +impl PartialEq for Error { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::Utf8Error(l), Self::Utf8Error(r)) => l == r, + // IO errors cannot be compared, but in the absence of any more + // meaningful way to compare the errors we compare the kind of error + // and ignore the embedded source error or OS error. The main use + // case for comparing errors outputted by the XDR library is for + // error case testing, and a lack of the ability to compare has a + // detrimental affect on failure testing, so this is a tradeoff. + #[cfg(feature = "std")] + (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), + _ => core::mem::discriminant(self) == core::mem::discriminant(other), + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] diff --git a/src/next.rs b/src/next.rs index c48e1c8f..bfcabb75 100644 --- a/src/next.rs +++ b/src/next.rs @@ -91,6 +91,9 @@ use std::{ io::{BufRead, BufReader, Cursor, Read, Write}, }; +/// Error contains all errors returned by functions in this crate. It can be +/// compared via `PartialEq`, however any contained IO errors will only be +/// compared on their `ErrorKind`. #[derive(Debug)] pub enum Error { Invalid, @@ -102,6 +105,23 @@ pub enum Error { Io(io::Error), } +impl PartialEq for Error { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::Utf8Error(l), Self::Utf8Error(r)) => l == r, + // IO errors cannot be compared, but in the absence of any more + // meaningful way to compare the errors we compare the kind of error + // and ignore the embedded source error or OS error. The main use + // case for comparing errors outputted by the XDR library is for + // error case testing, and a lack of the ability to compare has a + // detrimental affect on failure testing, so this is a tradeoff. + #[cfg(feature = "std")] + (Self::Io(l), Self::Io(r)) => l.kind() == r.kind(), + _ => core::mem::discriminant(self) == core::mem::discriminant(other), + } + } +} + #[cfg(feature = "std")] impl error::Error for Error { #[must_use] diff --git a/src/scmap.rs b/src/scmap.rs index 6acc36b8..4cb5bfe8 100644 --- a/src/scmap.rs +++ b/src/scmap.rs @@ -1,12 +1,11 @@ -#![allow(clippy::result_unit_err)] #![allow(clippy::missing_errors_doc)] -use crate::{ScMap, ScMapEntry, ScVal, Validate}; +use crate::{ScMap, ScMapEntry, ScVal, Validate, Error}; extern crate alloc; use alloc::vec::Vec; impl ScMap { - pub fn sorted_from_entries(entries: I) -> Result + pub fn sorted_from_entries(entries: I) -> Result where I: Iterator, { @@ -19,7 +18,7 @@ impl ScMap { Ok(m) } - pub fn sorted_from_pairs(pairs: I) -> Result + pub fn sorted_from_pairs(pairs: I) -> Result where K: Into, V: Into, @@ -31,7 +30,7 @@ impl ScMap { })) } - pub fn sorted_from(src: I) -> Result + pub fn sorted_from(src: I) -> Result where K: Into, V: Into, diff --git a/src/scval_validations.rs b/src/scval_validations.rs index ccc0d2c7..f8158f9f 100644 --- a/src/scval_validations.rs +++ b/src/scval_validations.rs @@ -1,6 +1,6 @@ #![allow(clippy::missing_errors_doc)] -use crate::{ScMap, ScObject, ScVal}; +use crate::{ScMap, ScObject, ScVal, Error}; pub trait Validate { type Error; @@ -8,7 +8,7 @@ pub trait Validate { } impl Validate for ScVal { - type Error = (); + type Error = Error; fn validate(&self) -> Result<(), Self::Error> { match self { @@ -17,7 +17,7 @@ impl Validate for ScVal { if *i >= 0 { Ok(()) } else { - Err(()) + Err(Error::Invalid) } } @@ -28,7 +28,7 @@ impl Validate for ScVal { { Ok(()) } else { - Err(()) + Err(Error::Invalid) } } @@ -37,11 +37,11 @@ impl Validate for ScVal { if b & 0x0fff_ffff_ffff_ffff == *b { Ok(()) } else { - Err(()) + Err(Error::Invalid) } } - ScVal::Object(None) => Err(()), + ScVal::Object(None) => Err(Error::Invalid), ScVal::Object(Some(o)) => match o { ScObject::Map(m) => m.validate(), @@ -63,7 +63,7 @@ impl Validate for ScVal { } impl Validate for ScMap { - type Error = (); + type Error = Error; fn validate(&self) -> Result<(), Self::Error> { // Check the map is sorted by key, and there are no keys that are @@ -71,36 +71,36 @@ impl Validate for ScMap { if self.windows(2).all(|w| w[0].key < w[1].key) { Ok(()) } else { - Err(()) + Err(Error::Invalid) } } } #[cfg(test)] mod test { - use crate::{ScVal, Validate}; + use crate::{ScVal, Validate, Error}; #[test] fn u63() { assert_eq!(ScVal::U63(0).validate(), Ok(())); assert_eq!(ScVal::U63(1).validate(), Ok(())); assert_eq!(ScVal::U63(i64::MAX).validate(), Ok(())); - assert_eq!(ScVal::U63(-1).validate(), Err(())); + assert_eq!(ScVal::U63(-1).validate(), Err(Error::Invalid)); } #[test] fn symbol() { assert_eq!(ScVal::Symbol("".try_into().unwrap()).validate(), Ok(())); assert_eq!(ScVal::Symbol("a0A_".try_into().unwrap()).validate(), Ok(())); - assert_eq!(ScVal::Symbol("]".try_into().unwrap()).validate(), Err(())); + assert_eq!(ScVal::Symbol("]".try_into().unwrap()).validate(), Err(Error::Invalid)); } #[test] fn bitset() { assert_eq!(ScVal::Bitset(0x0000_0000_0000_0000).validate(), Ok(())); assert_eq!(ScVal::Bitset(0x0fff_ffff_ffff_ffff).validate(), Ok(())); - assert_eq!(ScVal::Bitset(0x1000_0000_0000_0000).validate(), Err(())); - assert_eq!(ScVal::Bitset(0x1fff_ffff_ffff_ffff).validate(), Err(())); + assert_eq!(ScVal::Bitset(0x1000_0000_0000_0000).validate(), Err(Error::Invalid)); + assert_eq!(ScVal::Bitset(0x1fff_ffff_ffff_ffff).validate(), Err(Error::Invalid)); } #[test] @@ -163,7 +163,7 @@ mod test { .unwrap() )))) .validate(), - Err(()) + Err(Error::Invalid) ); assert_eq!( ScVal::Object(Some(ScObject::Map(ScMap( @@ -181,7 +181,7 @@ mod test { .unwrap() )))) .validate(), - Err(()) + Err(Error::Invalid) ); } } From a1a8d83f69e7ddb39200d9a510174301c70addde Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Wed, 20 Jul 2022 17:05:26 -0700 Subject: [PATCH 62/65] make maps work with TryInto impl too for supporting vecs --- src/scmap.rs | 15 ++++++++------- src/scval_conversions.rs | 18 +++++++++++++++++- src/scval_validations.rs | 19 ++++++++++++++----- 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/src/scmap.rs b/src/scmap.rs index 4cb5bfe8..7423c30f 100644 --- a/src/scmap.rs +++ b/src/scmap.rs @@ -1,6 +1,6 @@ #![allow(clippy::missing_errors_doc)] -use crate::{ScMap, ScMapEntry, ScVal, Validate, Error}; +use crate::{Error, ScMap, ScMapEntry, ScVal, Validate}; extern crate alloc; use alloc::vec::Vec; @@ -20,14 +20,15 @@ impl ScMap { pub fn sorted_from_pairs(pairs: I) -> Result where - K: Into, - V: Into, + K: TryInto, + V: TryInto, I: Iterator, { - Self::sorted_from_entries(pairs.map(|(key, val)| ScMapEntry { - key: key.into(), - val: val.into(), - })) + let entries = pairs + .map(<_ as TryInto>::try_into) + .collect::, _>>() + .map_err(|_| Error::Invalid)?; + Self::sorted_from_entries(entries.into_iter()) } pub fn sorted_from(src: I) -> Result diff --git a/src/scval_conversions.rs b/src/scval_conversions.rs index 9f405a72..224ca7cc 100644 --- a/src/scval_conversions.rs +++ b/src/scval_conversions.rs @@ -1,5 +1,6 @@ use crate::{ - Hash, PublicKey, ScBigInt, ScHash, ScMap, ScObject, ScStatic, ScStatus, ScSymbol, ScVal, ScVec, + Hash, PublicKey, ScBigInt, ScHash, ScMap, ScMapEntry, ScObject, ScStatic, ScStatus, ScSymbol, + ScVal, ScVec, }; #[cfg(all(not(feature = "std"), feature = "alloc"))] @@ -723,6 +724,21 @@ impl TryFrom for ScMap { } } +impl TryFrom<(K, V)> for ScMapEntry +where + K: TryInto, + V: TryInto, +{ + type Error = (); + + fn try_from(v: (K, V)) -> Result { + Ok(ScMapEntry { + key: v.0.try_into().map_err(|_| ())?, + val: v.1.try_into().map_err(|_| ())?, + }) + } +} + // TODO: Add conversions from std::collections::HashMap, im_rcOrdMap, and other // popular map types to ScMap. diff --git a/src/scval_validations.rs b/src/scval_validations.rs index f8158f9f..cecbffc4 100644 --- a/src/scval_validations.rs +++ b/src/scval_validations.rs @@ -1,6 +1,6 @@ #![allow(clippy::missing_errors_doc)] -use crate::{ScMap, ScObject, ScVal, Error}; +use crate::{Error, ScMap, ScObject, ScVal}; pub trait Validate { type Error; @@ -78,7 +78,7 @@ impl Validate for ScMap { #[cfg(test)] mod test { - use crate::{ScVal, Validate, Error}; + use crate::{Error, ScVal, Validate}; #[test] fn u63() { @@ -92,15 +92,24 @@ mod test { fn symbol() { assert_eq!(ScVal::Symbol("".try_into().unwrap()).validate(), Ok(())); assert_eq!(ScVal::Symbol("a0A_".try_into().unwrap()).validate(), Ok(())); - assert_eq!(ScVal::Symbol("]".try_into().unwrap()).validate(), Err(Error::Invalid)); + assert_eq!( + ScVal::Symbol("]".try_into().unwrap()).validate(), + Err(Error::Invalid) + ); } #[test] fn bitset() { assert_eq!(ScVal::Bitset(0x0000_0000_0000_0000).validate(), Ok(())); assert_eq!(ScVal::Bitset(0x0fff_ffff_ffff_ffff).validate(), Ok(())); - assert_eq!(ScVal::Bitset(0x1000_0000_0000_0000).validate(), Err(Error::Invalid)); - assert_eq!(ScVal::Bitset(0x1fff_ffff_ffff_ffff).validate(), Err(Error::Invalid)); + assert_eq!( + ScVal::Bitset(0x1000_0000_0000_0000).validate(), + Err(Error::Invalid) + ); + assert_eq!( + ScVal::Bitset(0x1fff_ffff_ffff_ffff).validate(), + Err(Error::Invalid) + ); } #[test] From 94e809744db0c4bb25acb498a3606f8c1dc44c91 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Wed, 20 Jul 2022 17:06:09 -0700 Subject: [PATCH 63/65] add todo --- src/scval_conversions.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/scval_conversions.rs b/src/scval_conversions.rs index 224ca7cc..012489e1 100644 --- a/src/scval_conversions.rs +++ b/src/scval_conversions.rs @@ -11,6 +11,8 @@ use alloc::{string::String, vec, vec::Vec}; #[cfg(feature = "num-bigint")] use num_bigint::{BigInt, Sign}; +// TODO: Use the Error type for conversions in this file. + impl From for ScVal { fn from(v: ScStatic) -> Self { Self::Static(v) From 4c91f59aa3052e9a4d141f5b85a6f53024d6be6b Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Wed, 20 Jul 2022 17:15:42 -0700 Subject: [PATCH 64/65] error wrangling --- src/scmap.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/scmap.rs b/src/scmap.rs index 7423c30f..3afaa198 100644 --- a/src/scmap.rs +++ b/src/scmap.rs @@ -5,11 +5,15 @@ extern crate alloc; use alloc::vec::Vec; impl ScMap { - pub fn sorted_from_entries(entries: I) -> Result + pub fn sorted_from_entries(entries: I) -> Result where - I: Iterator, + E: TryInto, + I: Iterator, { - let mut v: Vec = entries.collect(); + let mut v = entries + .map(TryInto::try_into) + .collect::, _>>() + .map_err(|_| Error::Invalid)?; // TODO: Add tests that prove order consistency of ScVal with RawVal. https://github.com/stellar/rs-stellar-xdr/issues/117 v.sort_by(|a, b| a.key.cmp(&b.key)); let m = ScMap(v.try_into()?); @@ -24,11 +28,7 @@ impl ScMap { V: TryInto, I: Iterator, { - let entries = pairs - .map(<_ as TryInto>::try_into) - .collect::, _>>() - .map_err(|_| Error::Invalid)?; - Self::sorted_from_entries(entries.into_iter()) + Self::sorted_from_entries(pairs) } pub fn sorted_from(src: I) -> Result From d16cab4cfd256a84f44b5fdc91fa9fbaaefe440e Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Wed, 20 Jul 2022 17:19:53 -0700 Subject: [PATCH 65/65] more general sorted_from --- src/scmap.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/scmap.rs b/src/scmap.rs index 3afaa198..904d5ef8 100644 --- a/src/scmap.rs +++ b/src/scmap.rs @@ -31,13 +31,12 @@ impl ScMap { Self::sorted_from_entries(pairs) } - pub fn sorted_from(src: I) -> Result + pub fn sorted_from(src: I) -> Result where - K: Into, - V: Into, - I: IntoIterator, + E: TryInto, + I: IntoIterator, { - Self::sorted_from_pairs(src.into_iter()) + Self::sorted_from_entries(src.into_iter()) } }