Skip to content

Addr ref helper #872

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 96 additions & 23 deletions packages/std/src/addresses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down Expand Up @@ -45,6 +47,17 @@ impl Addr {
pub fn unchecked<T: Into<String>>(input: T) -> Addr {
Addr(input.into())
}

#[inline]
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 {
Expand All @@ -53,13 +66,6 @@ impl fmt::Display for Addr {
}
}

impl AsRef<str> for Addr {
#[inline]
fn as_ref(&self) -> &str {
&self.0
}
}

/// Implement `Addr == &str`
impl PartialEq<&str> for Addr {
fn eq(&self, rhs: &&str) -> bool {
Expand All @@ -74,6 +80,12 @@ impl PartialEq<Addr> for &str {
}
}

impl<'a> PartialEq<AddrRef<'a>> for Addr {
fn eq(&self, rhs: &AddrRef<'a>) -> bool {
self.0.as_str() == rhs.as_str()
}
}

/// Implement `Addr == String`
impl PartialEq<String> for Addr {
fn eq(&self, rhs: &String) -> bool {
Expand Down Expand Up @@ -103,15 +115,47 @@ impl From<&Addr> for String {
}
}

impl From<Addr> for HumanAddr {
fn from(addr: Addr) -> Self {
HumanAddr(addr.0)
/// 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
#[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<Self> {
Ok(AddrRef(from_utf8(raw)?))
}

pub fn as_str(&self) -> &str {
self.0
}
}

impl From<&Addr> for HumanAddr {
fn from(addr: &Addr) -> Self {
HumanAddr(addr.0.clone())
impl<'a> From<&'a Addr> for AddrRef<'a> {
fn from(addr: &'a Addr) -> Self {
AddrRef(addr.as_str())
}
}

impl<'a> PartialEq<&str> for AddrRef<'a> {
fn eq(&self, rhs: &&str) -> bool {
self.0 == *rhs
}
}

impl<'a> From<AddrRef<'a>> for Addr {
fn from(addr: AddrRef<'a>) -> Self {
Addr(addr.0.to_string())
}
}

Expand Down Expand Up @@ -265,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");
Expand All @@ -288,6 +337,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");
Expand Down Expand Up @@ -323,17 +378,35 @@ mod tests {
}

#[test]
fn addr_implements_into_human_address() {
// owned Addr
let addr = Addr::unchecked("cos934gh9034hg04g0h134");
let human: HumanAddr = addr.into();
assert_eq!(human, "cos934gh9034hg04g0h134");
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");
}

// &Addr
let addr = Addr::unchecked("cos934gh9034hg04g0h134");
let addr_ref = &addr;
let human: HumanAddr = addr_ref.into();
assert_eq!(human, "cos934gh9034hg04g0h134");
#[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_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]
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
Expand Down