use ethprim::{Address, AsI256 as _, Digest, I256, U256};
pub type Word = [u8; 32];
pub trait Primitive {
fn to_word(&self) -> Word;
fn from_word(word: Word) -> Self;
}
macro_rules! impl_primitive_for_i256 {
($($t:ty,)*) => {$(
impl Primitive for $t {
fn to_word(&self) -> Word {
self.to_be_bytes()
}
fn from_word(word: Word) -> Self {
Self::from_be_bytes(word)
}
}
)*};
}
impl_primitive_for_i256! {
I256,
U256,
}
macro_rules! impl_primitive_for_integer {
($($t:ty,)*) => {$(
impl Primitive for $t {
fn to_word(&self) -> Word {
self.as_i256().to_word()
}
fn from_word(word: Word) -> Self {
*I256::from_word(word).low() as _
}
}
)*};
}
impl_primitive_for_integer! {
i8, i16, i32, i64, i128, isize,
u8, u16, u32, u64, u128, usize,
}
impl Primitive for bool {
fn to_word(&self) -> Word {
[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, *self as _,
]
}
fn from_word(word: Word) -> Self {
word != [0; 32]
}
}
impl Primitive for Address {
fn to_word(&self) -> Word {
let mut word = Word::default();
word[12..].copy_from_slice(&**self);
word
}
fn from_word(word: Word) -> Self {
Self::from_slice(&word[12..])
}
}
impl Primitive for Digest {
fn to_word(&self) -> Word {
**self
}
fn from_word(word: Word) -> Self {
Self(word)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sign_extends_integers() {
assert_eq!((1_i32).to_word(), {
let mut bytes = [0; 32];
bytes[31] = 1;
bytes
});
assert_eq!((-1_i32).to_word(), [0xff; 32]);
}
}