use cfg_if::cfg_if;
use core::{
fmt::{
self,
Debug,
Display,
Formatter,
},
ops::AddAssign,
};
#[cfg(feature = "std")]
use scale_info::{
build::Fields,
Path,
Type,
TypeInfo,
};
#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct Key([u8; 32]);
impl Key {
#[inline]
pub const fn new(bytes: [u8; 32]) -> Self {
Self(bytes)
}
}
impl From<[u8; 32]> for Key {
#[inline]
fn from(bytes: [u8; 32]) -> Self {
Self::new(bytes)
}
}
impl AsRef<[u8; 32]> for Key {
#[inline]
fn as_ref(&self) -> &[u8; 32] {
&self.0
}
}
impl AsMut<[u8; 32]> for Key {
#[inline]
fn as_mut(&mut self) -> &mut [u8; 32] {
&mut self.0
}
}
impl Key {
fn write_bytes(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "0x")?;
let bytes = self.as_ref();
let len_bytes = bytes.len();
let len_chunk = 4;
let len_chunks = len_bytes / len_chunk;
for i in 0..len_chunks {
let offset = i * len_chunk;
write!(
f,
"_{:02X}{:02X}{:02X}{:02X}",
bytes[offset],
bytes[offset + 1],
bytes[offset + 2],
bytes[offset + 3]
)?;
}
Ok(())
}
}
impl Debug for Key {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "Key(")?;
self.write_bytes(f)?;
write!(f, ")")?;
Ok(())
}
}
impl Display for Key {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.write_bytes(f)
}
}
impl Key {
#[cfg(target_endian = "little")]
fn reinterpret_as_u64x4(&self) -> &[u64; 4] {
unsafe { &*(&self.0 as *const [u8; 32] as *const [u64; 4]) }
}
#[cfg(target_endian = "little")]
fn reinterpret_as_u64x4_mut(&mut self) -> &mut [u64; 4] {
unsafe { &mut *(&mut self.0 as *mut [u8; 32] as *mut [u64; 4]) }
}
}
impl scale::Encode for Key {
#[inline]
fn size_hint(&self) -> usize {
32
}
#[inline]
fn encode_to<O>(&self, output: &mut O)
where
O: scale::Output + ?Sized,
{
output.write(self.as_ref());
}
#[inline]
fn using_encoded<R, F>(&self, f: F) -> R
where
F: FnOnce(&[u8]) -> R,
{
f(self.as_ref())
}
#[inline]
fn encoded_size(&self) -> usize {
self.size_hint()
}
}
impl scale::EncodeLike<[u8; 32]> for Key {}
impl scale::Decode for Key {
#[inline]
fn decode<I>(input: &mut I) -> Result<Self, scale::Error>
where
I: scale::Input,
{
let bytes = <[u8; 32] as scale::Decode>::decode(input)?;
Ok(Self::from(bytes))
}
#[inline]
fn encoded_fixed_size() -> Option<usize> {
Some(32)
}
}
#[cfg(feature = "std")]
impl TypeInfo for Key {
type Identity = Self;
fn type_info() -> Type {
Type::builder()
.path(Path::new("Key", "ink_primitives"))
.composite(
Fields::unnamed().field(|f| f.ty::<[u8; 32]>().type_name("[u8; 32]")),
)
}
}
impl Key {
#[cfg(target_endian = "little")]
fn add_assign_u64_le(&mut self, rhs: u64) {
let words = self.reinterpret_as_u64x4_mut();
let (res0, ovfl) = words[0].overflowing_add(rhs);
let (res1, ovfl) = words[1].overflowing_add(ovfl as u64);
let (res2, ovfl) = words[2].overflowing_add(ovfl as u64);
let (res3, _ovfl) = words[3].overflowing_add(ovfl as u64);
words[0] = res0;
words[1] = res1;
words[2] = res2;
words[3] = res3;
}
#[cfg(target_endian = "little")]
fn add_assign_u64_le_using(&self, rhs: u64, result: &mut Key) {
let input = self.reinterpret_as_u64x4();
let result = result.reinterpret_as_u64x4_mut();
let (res0, ovfl) = input[0].overflowing_add(rhs);
let (res1, ovfl) = input[1].overflowing_add(ovfl as u64);
let (res2, ovfl) = input[2].overflowing_add(ovfl as u64);
let (res3, _ovfl) = input[3].overflowing_add(ovfl as u64);
result[0] = res0;
result[1] = res1;
result[2] = res2;
result[3] = res3;
}
#[cfg(target_endian = "big")]
fn add_assign_u64_be(&mut self, rhs: u64) {
let rhs_bytes = rhs.to_be_bytes();
let lhs_bytes = self.as_mut();
let len_rhs = rhs_bytes.len();
let len_lhs = lhs_bytes.len();
let mut carry = 0;
for i in 0..len_rhs {
let (res, ovfl) =
lhs_bytes[i].overflowing_add(rhs_bytes[i].wrapping_add(carry));
lhs_bytes[i] = res;
carry = ovfl as u8;
}
for i in len_rhs..len_lhs {
let (res, ovfl) = lhs_bytes[i].overflowing_add(carry);
lhs_bytes[i] = res;
carry = ovfl as u8;
if carry == 0 {
return
}
}
}
#[cfg(target_endian = "big")]
fn add_assign_u64_be_using(&self, rhs: u64, result: &mut Key) {
let rhs_bytes = rhs.to_be_bytes();
let lhs_bytes = self.as_ref();
let result_bytes = result.as_mut();
let len_rhs = rhs_bytes.len();
let len_lhs = lhs_bytes.len();
let mut carry = 0;
for i in 0..len_rhs {
let (res, ovfl) =
lhs_bytes[i].overflowing_add(rhs_bytes[i].wrapping_add(carry));
result_bytes[i] = res;
carry = ovfl as u8;
}
for i in len_rhs..len_lhs {
let (res, ovfl) = lhs_bytes[i].overflowing_add(carry);
result_bytes[i] = res;
carry = ovfl as u8;
}
}
#[inline]
pub fn add_assign_using<T>(&self, rhs: T, result: &mut Key)
where
T: Into<u64>,
{
let rhs = rhs.into();
cfg_if! {
if #[cfg(target_endian = "little")] {
self.add_assign_u64_le_using(rhs, result);
} else {
self.add_assign_u64_be_using(rhs, result);
}
}
}
}
impl AddAssign<u64> for Key {
#[inline]
fn add_assign(&mut self, rhs: u64) {
cfg_if! {
if #[cfg(target_endian = "little")] {
self.add_assign_u64_le(rhs);
} else {
self.add_assign_u64_be(rhs);
}
}
}
}
impl AddAssign<&u64> for Key {
#[inline]
fn add_assign(&mut self, rhs: &u64) {
<Self as AddAssign<u64>>::add_assign(self, *rhs)
}
}