From 36e036d688a5f0c7a79c1d8edae02fd5dd00987d Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 9 Apr 2021 11:00:35 +0200 Subject: [PATCH 1/4] Remove Addr -> HumanAddr conversion --- packages/std/src/addresses.rs | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/packages/std/src/addresses.rs b/packages/std/src/addresses.rs index 953866db31..a91b7ecb7d 100644 --- a/packages/std/src/addresses.rs +++ b/packages/std/src/addresses.rs @@ -103,18 +103,6 @@ impl From<&Addr> for String { } } -impl From for HumanAddr { - fn from(addr: Addr) -> Self { - HumanAddr(addr.0) - } -} - -impl From<&Addr> for HumanAddr { - fn from(addr: &Addr) -> Self { - HumanAddr(addr.0.clone()) - } -} - #[deprecated( since = "0.14.0", note = "HumanAddr is not much more than an alias to String and it does not provide significant safety advantages. With CosmWasm 0.14, we now use String when there was HumanAddr before. There is also the new Addr, which holds a validated immutable human readable address." @@ -322,20 +310,6 @@ mod tests { assert_eq!(string, "cos934gh9034hg04g0h134"); } - #[test] - fn addr_implements_into_human_address() { - // owned Addr - let addr = Addr::unchecked("cos934gh9034hg04g0h134"); - let human: HumanAddr = addr.into(); - assert_eq!(human, "cos934gh9034hg04g0h134"); - - // &Addr - let addr = Addr::unchecked("cos934gh9034hg04g0h134"); - let addr_ref = &addr; - let human: HumanAddr = addr_ref.into(); - assert_eq!(human, "cos934gh9034hg04g0h134"); - } - // Test HumanAddr as_str() for each HumanAddr::from input type #[test] fn human_addr_as_str() { From 7feddeb091d89dfeca56fade9d9017b8b03bd64b Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 9 Apr 2021 11:02:53 +0200 Subject: [PATCH 2/4] Add as_str helper --- packages/std/src/addresses.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/std/src/addresses.rs b/packages/std/src/addresses.rs index a91b7ecb7d..82dea31355 100644 --- a/packages/std/src/addresses.rs +++ b/packages/std/src/addresses.rs @@ -45,6 +45,11 @@ impl Addr { pub fn unchecked>(input: T) -> Addr { Addr(input.into()) } + + #[inline] + pub fn as_str(&self) -> &str { + self.0.as_str() + } } impl fmt::Display for Addr { @@ -56,7 +61,7 @@ impl fmt::Display for Addr { impl AsRef for Addr { #[inline] fn as_ref(&self) -> &str { - &self.0 + self.as_str() } } @@ -276,6 +281,12 @@ mod tests { assert_eq!(addr.as_ref(), "literal-string"); } + #[test] + fn addr_as_str() { + let addr = Addr::unchecked("literal-string"); + assert_eq!(addr.as_str(), "literal-string"); + } + #[test] fn addr_implements_partial_eq_with_str() { let addr = Addr::unchecked("cos934gh9034hg04g0h134"); From 087ff923367370c55fafd74cd039658d27b3b53d Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 9 Apr 2021 11:20:23 +0200 Subject: [PATCH 3/4] Add basic AddrRef implementation --- packages/std/src/addresses.rs | 71 +++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/packages/std/src/addresses.rs b/packages/std/src/addresses.rs index 82dea31355..c39e8f5ad2 100644 --- a/packages/std/src/addresses.rs +++ b/packages/std/src/addresses.rs @@ -4,8 +4,10 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::fmt; use std::ops::Deref; +use std::str::from_utf8; use crate::binary::Binary; +use crate::errors::StdResult; /// A human readable address. /// @@ -79,6 +81,12 @@ impl PartialEq for &str { } } +impl<'a> PartialEq> for Addr { + fn eq(&self, rhs: &AddrRef<'a>) -> bool { + self.0.as_str() == rhs.as_str() + } +} + /// Implement `Addr == String` impl PartialEq for Addr { fn eq(&self, rhs: &String) -> bool { @@ -108,6 +116,45 @@ impl From<&Addr> for String { } } +/// AddrRef is like &Addr but can be created easily without requiring a heap allocation +/// It is not designed to be serialized but used internally, especially working with storage-plus keys +/// TODO: do we want PartialEqual methods here as well? +#[derive(Debug, Clone, Copy)] +pub struct AddrRef<'a>(&'a str); + +impl<'a> AddrRef<'a> { + /// the safe way to construct one from an address (also via From/Into helpers) + pub fn new(addr: &'a Addr) -> Self { + AddrRef(addr.as_str()) + } + + /// This should only be used in test code + pub const fn unchecked(addr: &'a str) -> Self { + AddrRef(addr) + } + + /// This is for parsing raw keys stored in the db we created previously with Addr + pub fn unchecked_utf8(raw: &'a [u8]) -> StdResult { + Ok(AddrRef(from_utf8(raw)?)) + } + + pub fn as_str(&self) -> &str { + self.0 + } +} + +impl<'a> From<&'a Addr> for AddrRef<'a> { + fn from(addr: &'a Addr) -> Self { + AddrRef(addr.as_ref()) + } +} + +impl<'a> From> for Addr { + fn from(addr: AddrRef<'a>) -> Self { + Addr(addr.0.to_string()) + } +} + #[deprecated( since = "0.14.0", note = "HumanAddr is not much more than an alias to String and it does not provide significant safety advantages. With CosmWasm 0.14, we now use String when there was HumanAddr before. There is also the new Addr, which holds a validated immutable human readable address." @@ -321,6 +368,30 @@ mod tests { assert_eq!(string, "cos934gh9034hg04g0h134"); } + #[test] + fn addr_ref_unchecked_from_literal() { + let addr_ref = AddrRef::unchecked("my-address"); + assert_eq!(addr_ref.as_str(), "my-address"); + } + + #[test] + fn addr_ref_unchecked_from_bytes() { + let addr_ref = AddrRef::unchecked_utf8(b"some-text").unwrap(); + assert_eq!(addr_ref.as_str(), "some-text"); + // returns an error if we pass bad data in ("Invalid 2 octet sequence") + AddrRef::unchecked_utf8(&[0xc3, 0x28]).unwrap_err(); + } + + #[test] + fn addr_ref_to_and_from_addr() { + let addr_ref = AddrRef::unchecked("foobar"); + let addr: Addr = addr_ref.into(); + // same strings + assert_eq!(addr.as_str(), addr_ref.as_str()); + // helper also works + assert_eq!(addr, addr_ref); + } + // Test HumanAddr as_str() for each HumanAddr::from input type #[test] fn human_addr_as_str() { From 329bd1921b77176ca5ec3d924094aa559b386f12 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 9 Apr 2021 11:29:09 +0200 Subject: [PATCH 4/4] Add useful helpers for Addr <-> AddrRef --- packages/std/src/addresses.rs | 37 +++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/packages/std/src/addresses.rs b/packages/std/src/addresses.rs index c39e8f5ad2..36052c90de 100644 --- a/packages/std/src/addresses.rs +++ b/packages/std/src/addresses.rs @@ -52,6 +52,12 @@ impl Addr { pub fn as_str(&self) -> &str { self.0.as_str() } + + /// This gets an AddrRef, much like OwnedDeps.as_ref + /// We don't implement AsRef as we want an object back, not &AddrRef + pub fn as_ref(&'_ self) -> AddrRef<'_> { + AddrRef(self.as_str()) + } } impl fmt::Display for Addr { @@ -60,13 +66,6 @@ impl fmt::Display for Addr { } } -impl AsRef for Addr { - #[inline] - fn as_ref(&self) -> &str { - self.as_str() - } -} - /// Implement `Addr == &str` impl PartialEq<&str> for Addr { fn eq(&self, rhs: &&str) -> bool { @@ -118,7 +117,6 @@ impl From<&Addr> for String { /// AddrRef is like &Addr but can be created easily without requiring a heap allocation /// It is not designed to be serialized but used internally, especially working with storage-plus keys -/// TODO: do we want PartialEqual methods here as well? #[derive(Debug, Clone, Copy)] pub struct AddrRef<'a>(&'a str); @@ -145,7 +143,13 @@ impl<'a> AddrRef<'a> { impl<'a> From<&'a Addr> for AddrRef<'a> { fn from(addr: &'a Addr) -> Self { - AddrRef(addr.as_ref()) + AddrRef(addr.as_str()) + } +} + +impl<'a> PartialEq<&str> for AddrRef<'a> { + fn eq(&self, rhs: &&str) -> bool { + self.0 == *rhs } } @@ -305,6 +309,11 @@ mod tests { use std::hash::{Hash, Hasher}; use std::iter::FromIterator; + // Let's see if we can get this directly from Addr + fn demo_deref(addr: AddrRef, compare: &str) { + assert_eq!(addr, compare); + } + #[test] fn addr_unchecked_works() { let a = Addr::unchecked("123"); @@ -372,6 +381,8 @@ mod tests { fn addr_ref_unchecked_from_literal() { let addr_ref = AddrRef::unchecked("my-address"); assert_eq!(addr_ref.as_str(), "my-address"); + // PartialEq also implemented + assert_eq!(addr_ref, "my-address"); } #[test] @@ -383,7 +394,7 @@ mod tests { } #[test] - fn addr_ref_to_and_from_addr() { + fn addr_ref_to_addr() { let addr_ref = AddrRef::unchecked("foobar"); let addr: Addr = addr_ref.into(); // same strings @@ -392,6 +403,12 @@ mod tests { assert_eq!(addr, addr_ref); } + #[test] + fn addr_to_addr_ref() { + let addr = Addr::unchecked("some-long-string"); + demo_deref(addr.as_ref(), "some-long-string"); + } + // Test HumanAddr as_str() for each HumanAddr::from input type #[test] fn human_addr_as_str() {