ethereum_mysql/
sql_fixed_bytes.rs1pub use alloy::primitives::FixedBytes;
2use std::ops::Deref;
3use std::str::FromStr;
4
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7
8#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
10#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
11pub struct SqlFixedBytes<const BYTES: usize>(FixedBytes<BYTES>);
12pub type SqlHash = SqlFixedBytes<32>;
14pub type SqlTopicHash = SqlFixedBytes<32>;
16
17impl<const BYTES: usize> SqlFixedBytes<BYTES> {
18 pub fn new(bytes: [u8; BYTES]) -> Self {
20 SqlFixedBytes(FixedBytes::new(bytes))
21 }
22
23 pub fn inner(&self) -> &FixedBytes<BYTES> {
25 &self.0
26 }
27
28 pub const ZERO: Self = SqlFixedBytes(FixedBytes::ZERO);
30
31 pub const fn from_bytes(bytes: FixedBytes<BYTES>) -> Self {
33 SqlFixedBytes(bytes)
34 }
35
36 pub fn to_address(&self) -> Option<crate::SqlAddress> {
39 if BYTES == 32 {
40 let bytes = self.0.as_slice();
41 if bytes[..12].iter().all(|&b| b == 0) {
43 let mut addr = [0u8; 20];
44 addr.copy_from_slice(&bytes[12..]);
45 return Some(crate::SqlAddress::new(addr));
46 }
47 }
48 None
49 }
50
51 pub fn to_u256(&self) -> crate::SqlU256 {
53 use crate::SqlU256;
54 use alloy::primitives::U256;
55 if BYTES == 32 {
56 let mut arr = [0u8; 32];
57 arr.copy_from_slice(self.0.as_slice());
58 SqlU256::from(U256::from_be_bytes(arr))
59 } else {
60 SqlU256::ZERO
62 }
63 }
64}
65
66impl<const BYTES: usize> AsRef<FixedBytes<BYTES>> for SqlFixedBytes<BYTES> {
67 fn as_ref(&self) -> &FixedBytes<BYTES> {
68 &self.0
69 }
70}
71
72impl<const BYTES: usize> Deref for SqlFixedBytes<BYTES> {
73 type Target = FixedBytes<BYTES>;
74
75 fn deref(&self) -> &Self::Target {
76 &self.0
77 }
78}
79
80impl<const BYTES: usize> From<FixedBytes<BYTES>> for SqlFixedBytes<BYTES> {
81 fn from(bytes: FixedBytes<BYTES>) -> Self {
82 SqlFixedBytes(bytes)
83 }
84}
85
86impl<const BYTES: usize> From<SqlFixedBytes<BYTES>> for FixedBytes<BYTES> {
87 fn from(sql_bytes: SqlFixedBytes<BYTES>) -> Self {
88 sql_bytes.0
89 }
90}
91
92impl<const BYTES: usize> FromStr for SqlFixedBytes<BYTES> {
93 type Err = <FixedBytes<BYTES> as FromStr>::Err;
94
95 fn from_str(s: &str) -> Result<Self, Self::Err> {
96 FixedBytes::<BYTES>::from_str(s).map(SqlFixedBytes)
97 }
98}
99
100impl<const BYTES: usize> std::fmt::Display for SqlFixedBytes<BYTES> {
101 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102 self.0.fmt(f)
103 }
104}
105
106impl<const BYTES: usize> Default for SqlFixedBytes<BYTES> {
107 fn default() -> Self {
108 Self::ZERO
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115 use alloy::primitives::FixedBytes;
116 use std::str::FromStr;
117
118 #[test]
119 fn test_from_str_and_display() {
120 let hex = "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef";
121 let val = SqlFixedBytes::<32>::from_str(hex).unwrap();
122 assert_eq!(val.to_string(), hex.to_lowercase());
123 }
124
125 #[test]
126 fn test_zero() {
127 let zero = SqlFixedBytes::<32>::ZERO;
128 assert_eq!(zero.inner().as_slice(), &[0u8; 32]);
129 }
130
131 #[test]
132 fn test_as_ref_and_deref() {
133 let hex = "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef";
134 let val = SqlFixedBytes::<32>::from_str(hex).unwrap();
135 let as_ref: &FixedBytes<32> = val.as_ref();
136 let deref: &FixedBytes<32> = &val;
137 assert_eq!(as_ref, deref);
138 }
139
140 #[cfg(feature = "serde")]
141 #[test]
142 fn test_serde() {
143 let hex = "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef";
144 let val = SqlFixedBytes::<32>::from_str(hex).unwrap();
145 let json = serde_json::to_string(&val).unwrap();
146 let de: SqlFixedBytes<32> = serde_json::from_str(&json).unwrap();
147 assert_eq!(val, de);
148 }
149
150 #[test]
151 fn test_fixed_bytes_5() {
152 let hex = "0x68656c6c6f"; let val = SqlFixedBytes::<5>::from_str(hex).unwrap();
154 assert_eq!(val.inner().as_slice(), b"hello");
155 assert_eq!(val.to_string(), hex);
156 }
157
158 #[test]
159 fn test_fixed_bytes_1() {
160 let hex = "0x01";
161 let val = SqlFixedBytes::<1>::from_str(hex).unwrap();
162 assert_eq!(val.inner().as_slice(), &[1u8]);
163 assert_eq!(val.to_string(), hex);
164 }
165
166 #[test]
167 fn test_fixed_bytes_0() {
168 let hex = "0x";
169 let val = SqlFixedBytes::<0>::from_str(hex).unwrap();
170 assert_eq!(val.inner().as_slice(), &[] as &[u8]);
171 assert_eq!(val.to_string(), hex);
172 }
173}