use super::{ConversionError, DecodeHexError, byte_char_to_digit};
use crate::stable_hash;
use serde::Deserialize;
use std::{fmt::Write, str::FromStr};
#[cfg(feature = "ethereum")]
mod sealed {
use super::*;
use ethereum_types::{U64, U128, U256, U512};
macro_rules! impl_conversion {
($($name: ident: $size: expr),+$(,)?) => {
$(
impl From<$name> for U<$size> {
fn from(h: $name) -> Self {
Self(h.0)
}
}
impl From<U<$size>> for $name {
fn from(h: U<$size>) -> Self {
Self(h.0)
}
}
)*
};
}
impl_conversion!(
U64: 1,
U128: 2,
U256: 4,
U512: 8,
);
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct U<const N: usize>([u64; N]);
impl<const N: usize> Default for U<N> {
fn default() -> Self {
Self([0; N])
}
}
impl<const N: usize> PartialOrd for U<N> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<const N: usize> Ord for U<N> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
for (s, o) in self.0.iter().rev().zip(other.0.iter().rev()) {
match s.cmp(o) {
std::cmp::Ordering::Equal => {}
c => return c,
}
}
std::cmp::Ordering::Equal
}
}
macro_rules! impl_from {
($int: ty) => {
impl<const N: usize> From<$int> for U<N> {
fn from(v: $int) -> Self {
let mut this = Self::default();
if let Some(f) = this.0.first_mut() {
*f = u64::from(v);
}
this
}
}
};
}
impl_from!(u8);
impl_from!(u16);
impl_from!(u32);
impl_from!(u64);
impl<const N: usize> From<[u64; N]> for U<N> {
fn from(array: [u64; N]) -> Self {
Self(array)
}
}
impl<const N: usize> TryFrom<&[u8]> for U<N> {
type Error = ConversionError;
fn try_from(b: &[u8]) -> Result<Self, Self::Error> {
Self::from_be_slice(b)
}
}
pub trait ByteArray: Sized {
const SIZE: usize;
type Array: Sized;
fn to_be_bytes(&self) -> Self::Array;
fn from_be_bytes(bytes: Self::Array) -> Self;
}
macro_rules! impl_byte_array {
($i: expr) => {
impl ByteArray for U<$i> {
const SIZE: usize = std::mem::size_of::<U<$i>>();
type Array = [u8; std::mem::size_of::<U<$i>>()];
fn to_be_bytes(&self) -> Self::Array {
let mut bytes = [0_u8; $i * 8];
for (big_endian, byte) in self.be_byte_iter().zip(bytes.iter_mut()) {
*byte = big_endian;
}
bytes
}
fn from_be_bytes(bytes: Self::Array) -> Self {
let mut dest = [0; $i];
for (chunk, dest) in bytes.chunks_exact(8).zip(dest.iter_mut().rev()) {
let mut u64_bytes = [0u8; 8];
u64_bytes.copy_from_slice(chunk);
*dest = u64::from_be_bytes(u64_bytes);
}
Self(dest)
}
}
};
}
impl_byte_array!(1);
impl_byte_array!(2);
impl_byte_array!(3);
impl_byte_array!(4);
impl_byte_array!(5);
impl_byte_array!(6);
impl_byte_array!(7);
impl_byte_array!(8);
impl_byte_array!(9);
impl_byte_array!(10);
impl_byte_array!(11);
impl_byte_array!(12);
impl_byte_array!(13);
impl_byte_array!(14);
impl_byte_array!(15);
impl_byte_array!(16);
impl<const N: usize> U<N>
where
U<N>: ByteArray,
{
pub fn to_be_bytes(&self) -> <Self as ByteArray>::Array {
<Self as ByteArray>::to_be_bytes(self)
}
pub fn from_be_bytes(bytes: <Self as ByteArray>::Array) -> Self {
<Self as ByteArray>::from_be_bytes(bytes)
}
}
impl<const N: usize> From<U<N>> for super::BigInt {
fn from(u: U<N>) -> Self {
Self::from(&u)
}
}
impl<const N: usize> From<&U<N>> for super::BigInt {
fn from(u: &U<N>) -> Self {
super::TRANSIENT_BYTES_SERIALIZER.with(|v| {
let mut vec = v.borrow_mut();
vec.clear();
vec.reserve(N * 8);
vec.extend(u.be_byte_iter());
let bi = super::BigInt::from_signed_bytes_be(&vec);
#[cfg(debug_assertions)]
{
if bi > super::BigInt::from(1_000_000_000_000_000_000_u128) {
tracing::warn!("BigInt conversion error. {u:?} -> {bi}");
}
}
bi
})
}
}
impl<const N: usize> U<N> {
const SIZE: usize = core::mem::size_of::<Self>();
pub const fn new(value: [u64; N]) -> Self {
Self(value)
}
pub fn low_32(&self) -> u32 {
self.0.first().copied().unwrap_or(0) as u32
}
pub fn low_64(&self) -> u64 {
self.0.first().copied().unwrap_or(0)
}
#[inline]
pub fn as_u32(&self) -> u32 {
assert!(
self.0.iter().skip(1).all(|v| *v == 0),
"{self:?} > u32::MAX"
);
u32::try_from(self.0.first().copied().unwrap_or(0)).unwrap()
}
#[inline]
pub fn as_u64(&self) -> u64 {
assert!(
self.0.iter().skip(1).all(|v| *v == 0),
"{self:?} > u64::MAX"
);
self.0.first().copied().unwrap_or(0)
}
#[inline]
pub fn as_u128(&self) -> u128 {
assert!(
self.0.iter().skip(2).all(|v| *v == 0),
"{self:?} > u128::MAX"
);
((self.0.get(1).copied().unwrap_or(0) as u128) << 64)
| self.0.first().copied().unwrap_or(0) as u128
}
pub fn from_be_slice(slice: &[u8]) -> Result<Self, ConversionError> {
if slice.len() > N * 8 {
return Err(ConversionError::WrongSize {
expected: Self::SIZE,
actual: slice.len(),
});
}
let mut dest = [0; N];
for (chunk, dest) in slice.rchunks(8).zip(dest.iter_mut()) {
let mut u64_bytes = [0u8; 8];
u64_bytes[8 - chunk.len()..].copy_from_slice(chunk);
*dest = u64::from_be_bytes(u64_bytes);
}
Ok(Self(dest))
}
pub const fn from_hex_str(s: &str) -> Self {
let s_bytes = s.as_bytes();
let mut inner = [0_u64; N];
if s_bytes.is_empty() {
return Self(inner);
}
if s_bytes.len() & 1 == 1 {
panic!("odd length str");
}
let skip_bytes = if s_bytes[0] == b'0' && (s_bytes[1] == b'x' || s_bytes[1] == b'X') {
2
} else {
0
};
if s_bytes.len() > skip_bytes + N * 16 {
panic!("hex str too long");
}
let mut count = 0;
while count * 16 + skip_bytes < s_bytes.len() {
let mut offset = s_bytes.len() - count * 16;
let mut val = 0;
let mut shift = 0;
while offset > skip_bytes && shift < 64 {
val |= (byte_char_to_digit(s_bytes[offset - 1]) as u64) << shift;
shift += 4;
offset -= 1;
}
inner[count] = val;
count += 1;
}
Self(inner)
}
pub const fn is_zero(&self) -> bool {
let mut i = 0;
while i < N {
if self.0[i] != 0 {
return false;
}
i += 1;
}
true
}
pub fn be_byte_iter(&self) -> impl Iterator<Item = u8> + '_ {
self.0.iter().rev().copied().flat_map(u64::to_be_bytes)
}
pub const fn into_inner(self) -> [u64; N] {
self.0
}
pub fn friendly_name() -> String {
format!("U{}", N * 64)
}
}
impl<const N: usize> FromStr for U<N> {
type Err = DecodeHexError;
fn from_str(mut s: &str) -> Result<Self, Self::Err> {
let mut is_negative = false;
if s.starts_with('-') {
is_negative = true;
s = &s[1..];
}
let extra_len = if s.starts_with("0x") || s.starts_with("0X") {
s = &s[2..];
2
} else {
0
} + usize::from(is_negative);
if s.len() > N * 16 {
return Err(DecodeHexError::WrongSize {
expected: N * 16 + extra_len,
actual: s.len(),
});
}
let mut output = Self::default();
for (chars, word) in s.as_bytes().rchunks(16).zip(output.0.iter_mut()) {
let mut be_bytes = [0_u8; 8];
for (c, byte) in chars.rchunks(2).zip(be_bytes.iter_mut().rev()) {
let (l, r) = match c {
&[l, r] => (l as char, r as char),
&[r] => ('0', r as char),
[..] => unreachable!(),
};
match (l.to_digit(16), r.to_digit(16)) {
(Some(l), Some(r)) => *byte = (l as u8) << 4 | r as u8,
(_, _) => return Err(DecodeHexError::WrongCharacter(l, r)),
};
}
*word = u64::from_be_bytes(be_bytes);
}
if is_negative {
for word in &mut output.0 {
*word = !*word;
}
for word in &mut output.0 {
let (new, overflow) = word.overflowing_add(1);
*word = new;
if !overflow {
break;
}
}
}
Ok(output)
}
}
impl<const N: usize> ::core::fmt::Debug for U<N> {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
<Self as ::core::fmt::Display>::fmt(self, f)
}
}
impl<const N: usize> ::core::fmt::Display for U<N> {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
write!(f, "0x")?;
<Self as ::core::fmt::LowerHex>::fmt(self, f)
}
}
impl<const N: usize> ::core::fmt::Binary for U<N> {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
let mut written = false;
let not_alternate = !f.alternate();
for byte in self.be_byte_iter().skip_while(|b| not_alternate && *b == 0) {
if written || f.alternate() {
write!(f, "{:08b}", byte)?;
} else {
write!(f, "{:b}", byte)?;
}
written = true;
}
if !written {
f.write_char('0')?;
}
Ok(())
}
}
impl<const N: usize> ::core::fmt::LowerHex for U<N> {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
let not_alternate = !f.alternate();
for byte in self.be_byte_iter().skip_while(|b| not_alternate && *b == 0) {
write!(f, "{:02x}", byte)?;
}
Ok(())
}
}
impl<const N: usize> ::core::fmt::UpperHex for U<N> {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
let not_alternate = !f.alternate();
for byte in self.be_byte_iter().skip_while(|b| not_alternate && *b == 0) {
write!(f, "{:02X}", byte)?;
}
Ok(())
}
}
mod sql {
use super::*;
use sqlx::{
Decode, Encode, Postgres, Type,
postgres::{PgHasArrayType, PgTypeInfo},
};
impl<const N: usize> From<U<N>> for sqlx::types::BigDecimal {
fn from(u: U<N>) -> Self {
sqlx::types::BigDecimal::new(crate::types::BigInt::from(u).into_inner(), 0)
}
}
impl<const N: usize> Type<Postgres> for U<N> {
fn type_info() -> PgTypeInfo {
<[u8] as sqlx::Type<Postgres>>::type_info()
}
fn compatible(ty: &PgTypeInfo) -> bool {
<[u8] as sqlx::Type<Postgres>>::compatible(ty)
}
}
impl<'a, const N: usize> Encode<'a, Postgres> for U<N> {
fn encode_by_ref(
&self,
buf: &mut <Postgres as sqlx::Database>::ArgumentBuffer<'a>,
) -> Result<sqlx::encode::IsNull, Box<dyn std::error::Error + Send + Sync + 'static>> {
super::super::TRANSIENT_BYTES_SERIALIZER.with(|v| {
let mut vec = v.borrow_mut();
vec.clear();
vec.reserve(N * 8);
vec.extend(self.be_byte_iter().skip_while(|b| *b == 0));
<&[u8] as sqlx::Encode<Postgres>>::encode_by_ref(&&vec[..], buf)
})
}
}
impl<'a, const N: usize> Decode<'a, Postgres> for U<N> {
fn decode(
value: <Postgres as sqlx::Database>::ValueRef<'a>,
) -> Result<Self, sqlx::error::BoxDynError> {
let decoded = <&'a [u8] as sqlx::Decode<Postgres>>::decode(value)?;
Ok(Self::from_be_slice(decoded)?)
}
}
impl<const N: usize> PgHasArrayType for U<N> {
fn array_type_info() -> PgTypeInfo {
<Vec<u8> as PgHasArrayType>::array_type_info()
}
}
}
mod graphql {
use super::*;
use std::borrow::Cow;
impl<const N: usize> async_graphql::OutputType for U<N> {
fn type_name() -> std::borrow::Cow<'static, str> {
Self::friendly_name().into()
}
fn create_type_info(registry: &mut async_graphql::registry::Registry) -> String {
<String>::create_type_info(registry)
}
async fn resolve(
&self,
_ctx: &async_graphql::ContextSelectionSet<'_>,
_field: &async_graphql::Positioned<async_graphql::parser::types::Field>,
) -> async_graphql::ServerResult<async_graphql::Value> {
Ok(async_graphql::Value::String(self.to_string()))
}
}
impl<const N: usize> async_graphql::InputType for U<N> {
type RawValueType = Self;
fn type_name() -> Cow<'static, str> {
Self::friendly_name().into()
}
fn create_type_info(registry: &mut async_graphql::registry::Registry) -> String {
registry.create_input_type::<Self, _>(async_graphql::registry::MetaTypeId::Scalar, |_| {
async_graphql::registry::MetaType::Scalar {
name: Self::type_name().into_owned(),
description: None,
visible: None,
is_valid: None,
specified_by_url: None,
inaccessible: false,
tags: vec![],
directive_invocations: vec![],
}
})
}
fn parse(value: Option<async_graphql::Value>) -> async_graphql::InputValueResult<Self> {
match value.unwrap_or_default() {
async_graphql::Value::String(v) => v
.parse::<Self>()
.map_err(async_graphql::InputValueError::custom),
async_graphql::Value::Binary(bytes) => {
Self::from_be_slice(&bytes).map_err(async_graphql::InputValueError::custom)
}
async_graphql::Value::Number(n) => {
Ok(Self::from(n.as_u64().ok_or_else(|| {
async_graphql::InputValueError::custom("expected unsigned integer")
})?))
}
_ => Err(async_graphql::InputValueError::custom(
"Only supports hex strings or byte arrays",
)),
}
}
fn to_value(&self) -> async_graphql::Value {
async_graphql::Value::String(self.to_string())
}
fn as_raw_value(&self) -> Option<&Self::RawValueType> {
Some(self)
}
}
}
impl<const N: usize> serde::Serialize for U<N> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
if serializer.is_human_readable() {
let size = N * 2 + 2;
super::TRANSIENT_STRING_SERIALIZER.with(|s| {
let mut s = s.borrow_mut();
s.clear();
s.reserve(size);
write!(s, "{:#?}", self).unwrap();
s.serialize(serializer)
})
} else {
self.0.serialize(serializer)
}
}
}
impl<'de, const N: usize> Deserialize<'de> for U<N> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::Error;
if deserializer.is_human_readable() {
let s = <&str>::deserialize(deserializer)?;
s.parse::<Self>().map_err(D::Error::custom)
} else {
let x = <&[u8]>::deserialize(deserializer)?;
Self::from_be_slice(x).map_err(D::Error::custom)
}
}
}
#[test]
fn test_from_hex_str() {
let zero = U::<4>::from_hex_str("");
assert!(zero.is_zero());
let zero = U::<2>::from_hex_str("0x");
assert!(zero.is_zero());
let zero = U::<1>::from_hex_str("0x00");
assert!(zero.is_zero());
const B: U<6> = U::<6>::from_hex_str(
"0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
);
let hex: u64 = 0x0123456789abcdef;
assert_eq!(U([hex, hex, hex, hex, hex, hex]), B);
let b = U::from_hex_str("0x0123456789abcdef0123456789abcdef");
assert_eq!(U([hex, hex, 0]), b);
let c = U::from_hex_str("0x01");
assert_eq!(U([1, 0]), c);
let c = U::from_hex_str("0x02020000000000000101");
assert_eq!(U([0x0101, 0x0202]), c);
}
#[test]
fn test_parse() {
let zero = U::<4>::from_str("").unwrap();
assert!(zero.is_zero());
let zero = U::<2>::from_str("0x").unwrap();
assert!(zero.is_zero());
let zero = U::<1>::from_str("0x00").unwrap();
assert!(zero.is_zero());
let b = U::<6>::from_str("0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef").unwrap();
let hex: u64 = 0x0123456789abcdef;
assert_eq!(U([hex, hex, hex, hex, hex, hex]), b);
let b = U::from_str("0x0123456789abcdef0123456789abcdef").unwrap();
assert_eq!(U([hex, hex, 0]), b);
let c = U::from_str("0x01").unwrap();
assert_eq!(U([1, 0]), c);
let c = U::from_str("0x02020000000000000101").unwrap();
assert_eq!(U([0x0101, 0x0202]), c);
}
#[test]
fn test_display_debug() {
let zero = U::<1>::from(0_u8);
assert_eq!(format!("{zero}").as_str(), "0x");
assert_eq!(format!("{zero:?}").as_str(), "0x");
assert_eq!(format!("{zero:#}").as_str(), "0x0000000000000000");
assert_eq!(format!("{zero:#?}").as_str(), "0x0000000000000000");
let hex: u64 = 0x0023456789abcdef;
let b = U([hex, hex, hex, hex, hex, hex]);
assert_eq!(
format!("{b}").as_str(),
"0x23456789abcdef0023456789abcdef0023456789abcdef0023456789abcdef0023456789abcdef0023456789abcdef"
);
assert_eq!(
format!("{b:#?}").as_str(),
"0x0023456789abcdef0023456789abcdef0023456789abcdef0023456789abcdef0023456789abcdef0023456789abcdef"
);
let b = U([0x98765453deadbeef, 0xfaceaced12390348, 0]);
assert_eq!(
format!("{b}").as_str(),
"0xfaceaced1239034898765453deadbeef"
);
assert_eq!(
format!("{b:#}").as_str(),
"0x0000000000000000faceaced1239034898765453deadbeef"
);
let c = U([1, 0]);
assert_eq!(format!("{c}"), "0x01");
assert_eq!(format!("{c:#?}"), "0x00000000000000000000000000000001");
let c = U([0x0101, 0x0202]);
assert_eq!(format!("{c:?}"), "0x02020000000000000101");
assert_eq!(format!("{c:#}"), "0x00000000000002020000000000000101");
}
#[test]
fn test_binary_hex() {
let zero = U::<1>::from(0xcf_u8);
assert_eq!(format!("{zero:x}").as_str(), "cf");
assert_eq!(format!("{zero:#x}").as_str(), "00000000000000cf");
assert_eq!(format!("{zero:X}").as_str(), "CF");
assert_eq!(format!("{zero:#X}").as_str(), "00000000000000CF");
assert_eq!(format!("{zero:b}").as_str(), "11001111");
assert_eq!(
format!("{zero:#b}").as_str(),
"0000000000000000000000000000000000000000000000000000000011001111"
);
}
#[test]
fn test_negative_hex() {
let expected =
U::<4>::from_hex_str("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3a6c");
let expected_2 = U::<4>::from_hex_str("0xffffffffffffffffffffffffffffffffffffffffffff3a6c0000000000000000");
let parse = ["-c594", "-0xc594", "-c5940000000000000000"];
let compare = [&expected, &expected, &expected_2];
let failed_parse = ["0x-c594"];
for (p, e) in parse.into_iter().zip(compare) {
let v = p.parse::<U<4>>().unwrap();
assert_eq!(&v, e);
}
for f in failed_parse {
f.parse::<U<4>>().unwrap_err();
}
}
#[test]
fn test_negative_bigint_conversion() {
let lower_tick =
U::<4>::from_hex_str("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb768");
let upper_tick =
U::<4>::from_hex_str("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffece60");
let lower_tick_expected = crate::types::BigInt::from(-84120_i32);
let upper_tick_expected = crate::types::BigInt::from(-78240_i32);
let lower_tick_bi = crate::types::BigInt::from(lower_tick);
assert_eq!(lower_tick_bi, lower_tick_expected);
let upper_tick_bi = crate::types::BigInt::from(upper_tick);
assert_eq!(upper_tick_bi, upper_tick_expected);
let starts_with_negative = U::<1>::from_hex_str("00000000fffece60");
let starts_with_negative_expected = crate::types::BigInt::from(4294889056_u32);
let starts_with_negative_bi = crate::types::BigInt::from(starts_with_negative);
assert_eq!(starts_with_negative_bi, starts_with_negative_expected);
}
impl<const N: usize> stable_hash::StableHash for U<N>
where
U<N>: ByteArray,
<U<N> as ByteArray>::Array: AsRef<[u8]>,
{
fn stable_hash<H: stable_hash::StableHasher>(&self, field_address: H::Addr, state: &mut H) {
let bytes = self.to_be_bytes();
stable_hash::utils::AsBytes(bytes.as_ref()).stable_hash(field_address, state);
}
}