Repository: gakonst/ethers-rs
Pull request #1421 (2022-06-28 12:56:54)

chore(core): convenience impls for Bytes
<!--
Thank you for your Pull Request. Please provide a description above and review
the requirements below.

Bug fixes and new features should include tests.

Contributors guide: https://github.com/gakonst/ethers-rs/blob/master/CONTRIBUTING.md

The contributors guide includes instructions for running rustfmt and building the
documentation.
-->

## Motivation
add some missing imples for the `ethers::Bytes` new type
<!--
Explain the context and why you're making that change. What is the problem
you're trying to solve? In some cases there is not a problem and this can be
thought of as being the motivation for your change.
-->

## Solution

<!--
Summarize the solution and provide any necessary context needed to understand
the code change.
-->

## PR Checklist

- [ ] Added Tests
- [ ] Added Documentation
- [ ] Updated the changelog



Patch:
diff --git a/ethers-core/src/abi/codec.rs b/ethers-core/src/abi/codec.rs
index d9f6c456..6a888aa0 100644
--- a/ethers-core/src/abi/codec.rs
+++ b/ethers-core/src/abi/codec.rs
@@ -57,6 +57,7 @@ macro_rules! impl_abi_codec {
 impl_abi_codec!(
     Vec<u8>,
     Bytes,
+    bytes::Bytes,
     Address,
     bool,
     String,
diff --git a/ethers-core/src/abi/mod.rs b/ethers-core/src/abi/mod.rs
index 7b9c34ac..4a332e6d 100644
--- a/ethers-core/src/abi/mod.rs
+++ b/ethers-core/src/abi/mod.rs
@@ -125,6 +125,7 @@ macro_rules! impl_abi_type {
 
 impl_abi_type!(
     Bytes => Bytes,
+    bytes::Bytes => Bytes,
     Vec<u8> =>  Array(Box::new(ParamType::Uint(8))),
     Address => Address,
     bool => Bool,
diff --git a/ethers-core/src/abi/tokens.rs b/ethers-core/src/abi/tokens.rs
index ca567078..e0684bb0 100644
--- a/ethers-core/src/abi/tokens.rs
+++ b/ethers-core/src/abi/tokens.rs
@@ -159,6 +159,19 @@ impl Tokenizable for Bytes {
     }
 }
 
+impl Tokenizable for bytes::Bytes {
+    fn from_token(token: Token) -> Result<Self, InvalidOutputType> {
+        match token {
+            Token::Bytes(s) => Ok(s.into()),
+            other => Err(InvalidOutputType(format!("Expected `Bytes`, got {:?}", other))),
+        }
+    }
+
+    fn into_token(self) -> Token {
+        Token::Bytes(self.to_vec())
+    }
+}
+
 impl Tokenizable for H256 {
     fn from_token(token: Token) -> Result<Self, InvalidOutputType> {
         match token {
@@ -287,7 +300,7 @@ macro_rules! tokenizable_item {
 
 tokenizable_item! {
     Token, String, Address, H256, U256, I256, U128, bool, Vec<u8>,
-    i8, i16, i32, i64, i128, u16, u32, u64, u128, Bytes,
+    i8, i16, i32, i64, i128, u16, u32, u64, u128, Bytes, bytes::Bytes,
 }
 
 macro_rules! impl_tokenizable_item_tuple {
diff --git a/ethers-core/src/types/bytes.rs b/ethers-core/src/types/bytes.rs
index d8728362..35c0e28d 100644
--- a/ethers-core/src/types/bytes.rs
+++ b/ethers-core/src/types/bytes.rs
@@ -2,8 +2,10 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
 use thiserror::Error;
 
 use std::{
+    borrow::Borrow,
     clone::Clone,
     fmt::{Debug, Display, Formatter, LowerHex, Result as FmtResult},
+    ops::Deref,
     str::FromStr,
 };
 
@@ -36,12 +38,45 @@ impl Bytes {
     }
 }
 
+impl Deref for Bytes {
+    type Target = [u8];
+
+    #[inline]
+    fn deref(&self) -> &[u8] {
+        self.as_ref()
+    }
+}
+
 impl AsRef<[u8]> for Bytes {
     fn as_ref(&self) -> &[u8] {
         self.0.as_ref()
     }
 }
 
+impl Borrow<[u8]> for Bytes {
+    fn borrow(&self) -> &[u8] {
+        self.as_ref()
+    }
+}
+
+impl IntoIterator for Bytes {
+    type Item = u8;
+    type IntoIter = bytes::buf::IntoIter<bytes::Bytes>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.0.into_iter()
+    }
+}
+
+impl<'a> IntoIterator for &'a Bytes {
+    type Item = &'a u8;
+    type IntoIter = core::slice::Iter<'a, u8>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.as_ref().iter()
+    }
+}
+
 impl From<bytes::Bytes> for Bytes {
     fn from(src: bytes::Bytes) -> Self {
         Self(src)
@@ -66,6 +101,36 @@ impl<'a, const N: usize> From<&'a [u8; N]> for Bytes {
     }
 }
 
+impl PartialEq<[u8]> for Bytes {
+    fn eq(&self, other: &[u8]) -> bool {
+        self.as_ref() == other
+    }
+}
+
+impl PartialEq<Bytes> for [u8] {
+    fn eq(&self, other: &Bytes) -> bool {
+        *other == *self
+    }
+}
+
+impl PartialEq<Vec<u8>> for Bytes {
+    fn eq(&self, other: &Vec<u8>) -> bool {
+        self.as_ref() == &other[..]
+    }
+}
+
+impl PartialEq<Bytes> for Vec<u8> {
+    fn eq(&self, other: &Bytes) -> bool {
+        *other == *self
+    }
+}
+
+impl PartialEq<bytes::Bytes> for Bytes {
+    fn eq(&self, other: &bytes::Bytes) -> bool {
+        other == self.as_ref()
+    }
+}
+
 #[derive(Debug, Clone, Error)]
 #[error("Failed to parse bytes: {0}")]
 pub struct ParseBytesError(String);


Test patch:
diff --git a/ethers-contract/tests/abigen.rs b/ethers-contract/tests/abigen.rs
index b5d6ded5..63a55ce0 100644
--- a/ethers-contract/tests/abigen.rs
+++ b/ethers-contract/tests/abigen.rs
@@ -189,18 +189,18 @@ fn can_gen_human_readable_with_structs() {
 
     let call = BarCall { x: 1u64.into(), y: 0u64.into(), addr: Address::random() };
     let encoded_call = contract.encode("bar", (call.x, call.y, call.addr)).unwrap();
-    assert_eq!(encoded_call, call.clone().encode().into());
+    assert_eq!(encoded_call, call.clone().encode());
     let decoded_call = BarCall::decode(encoded_call.as_ref()).unwrap();
     assert_eq!(call, decoded_call);
 
     let contract_call = SimpleContractCalls::Bar(call);
     let decoded_enum = SimpleContractCalls::decode(encoded_call.as_ref()).unwrap();
     assert_eq!(contract_call, decoded_enum);
-    assert_eq!(encoded_call, contract_call.encode().into());
+    assert_eq!(encoded_call, contract_call.encode());
 
     let call = YeetCall(1u64.into(), 0u64.into(), Address::zero());
     let encoded_call = contract.encode("yeet", (call.0, call.1, call.2)).unwrap();
-    assert_eq!(encoded_call, call.clone().encode().into());
+    assert_eq!(encoded_call, call.clone().encode());
     let decoded_call = YeetCall::decode(encoded_call.as_ref()).unwrap();
     assert_eq!(call, decoded_call);
 
@@ -208,7 +208,7 @@ fn can_gen_human_readable_with_structs() {
     let decoded_enum = SimpleContractCalls::decode(encoded_call.as_ref()).unwrap();
     assert_eq!(contract_call, decoded_enum);
     assert_eq!(contract_call, call.into());
-    assert_eq!(encoded_call, contract_call.encode().into());
+    assert_eq!(encoded_call, contract_call.encode());
 }
 
 #[test]
@@ -235,26 +235,26 @@ fn can_handle_overloaded_functions() {
     let call = GetValueCall;
 
     let encoded_call = contract.encode("getValue", ()).unwrap();
-    assert_eq!(encoded_call, call.clone().encode().into());
+    assert_eq!(encoded_call, call.clone().encode());
     let decoded_call = GetValueCall::decode(encoded_call.as_ref()).unwrap();
     assert_eq!(call, decoded_call);
 
     let contract_call = SimpleContractCalls::GetValue(call);
     let decoded_enum = SimpleContractCalls::decode(encoded_call.as_ref()).unwrap();
     assert_eq!(contract_call, decoded_enum);
-    assert_eq!(encoded_call, contract_call.encode().into());
+    assert_eq!(encoded_call, contract_call.encode());
 
     let call = GetValueWithOtherValueCall { other_value: 420u64.into() };
 
     let encoded_call = contract.encode_with_selector([15, 244, 201, 22], call.other_value).unwrap();
-    assert_eq!(encoded_call, call.clone().encode().into());
+    assert_eq!(encoded_call, call.clone().encode());
     let decoded_call = GetValueWithOtherValueCall::decode(encoded_call.as_ref()).unwrap();
     assert_eq!(call, decoded_call);
 
     let contract_call = SimpleContractCalls::GetValueWithOtherValue(call);
     let decoded_enum = SimpleContractCalls::decode(encoded_call.as_ref()).unwrap();
     assert_eq!(contract_call, decoded_enum);
-    assert_eq!(encoded_call, contract_call.encode().into());
+    assert_eq!(encoded_call, contract_call.encode());
 
     let call =
         GetValueWithOtherValueAndAddrCall { other_value: 420u64.into(), addr: Address::random() };
@@ -267,7 +267,7 @@ fn can_handle_overloaded_functions() {
     let contract_call = SimpleContractCalls::GetValueWithOtherValueAndAddr(call);
     let decoded_enum = SimpleContractCalls::decode(encoded_call.as_ref()).unwrap();
     assert_eq!(contract_call, decoded_enum);
-    assert_eq!(encoded_call, contract_call.encode().into());
+    assert_eq!(encoded_call, contract_call.encode());
 
     let call = SetValue0Call("message".to_string());
     let _contract_call = SimpleContractCalls::SetValue0(call);
@@ -443,7 +443,7 @@ fn can_generate_nested_types() {
 
     let call = MyfunCall { a: a.clone() };
     let encoded_call = contract.encode("myfun", (a,)).unwrap();
-    assert_eq!(encoded_call, call.clone().encode().into());
+    assert_eq!(encoded_call, call.clone().encode());
     let decoded_call = MyfunCall::decode(encoded_call.as_ref()).unwrap();
     assert_eq!(call, decoded_call);
 }