use crate::{AzothError, Result};
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct U256([u64; 4]);
impl PartialOrd for U256 {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for U256 {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
for i in (0..4).rev() {
match self.0[i].cmp(&other.0[i]) {
std::cmp::Ordering::Equal => continue,
ord => return ord,
}
}
std::cmp::Ordering::Equal
}
}
impl U256 {
pub fn zero() -> Self {
Self([0; 4])
}
pub fn from_u64(value: u64) -> Self {
Self([value, 0, 0, 0])
}
pub fn to_bytes(&self) -> [u8; 32] {
let mut bytes = [0u8; 32];
for (i, &word) in self.0.iter().enumerate() {
bytes[i * 8..(i + 1) * 8].copy_from_slice(&word.to_le_bytes());
}
bytes
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
if bytes.len() != 32 {
return Err(AzothError::Serialization(
"U256 requires exactly 32 bytes".into(),
));
}
let mut words = [0u64; 4];
for (i, word) in words.iter_mut().enumerate() {
let start = i * 8;
let end = start + 8;
*word = u64::from_le_bytes(bytes[start..end].try_into().unwrap());
}
Ok(Self(words))
}
#[allow(clippy::needless_range_loop)]
pub fn checked_add(&self, other: &Self) -> Option<Self> {
let mut result = [0u64; 4];
let mut carry = 0u128;
for i in 0..4 {
let sum = self.0[i] as u128 + other.0[i] as u128 + carry;
result[i] = sum as u64;
carry = sum >> 64;
}
if carry != 0 {
None
} else {
Some(Self(result))
}
}
#[allow(clippy::needless_range_loop)]
pub fn checked_sub(&self, other: &Self) -> Option<Self> {
let mut result = [0u64; 4];
let mut borrow = 0i128;
for i in 0..4 {
let diff = self.0[i] as i128 - other.0[i] as i128 - borrow;
if diff < 0 {
result[i] = (diff + (1i128 << 64)) as u64;
borrow = 1;
} else {
result[i] = diff as u64;
borrow = 0;
}
}
if borrow != 0 {
None
} else {
Some(Self(result))
}
}
}
impl From<u64> for U256 {
fn from(value: u64) -> Self {
Self::from_u64(value)
}
}
impl U256 {
pub fn as_limbs(&self) -> &[u64; 4] {
&self.0
}
pub fn from_limbs(limbs: [u64; 4]) -> Self {
Self(limbs)
}
}
#[cfg(feature = "alloy")]
mod alloy_interop {
use super::U256;
impl From<alloy_primitives::U256> for U256 {
fn from(v: alloy_primitives::U256) -> Self {
let limbs: [u64; 4] = v.into_limbs();
U256::from_limbs(limbs)
}
}
impl From<U256> for alloy_primitives::U256 {
fn from(v: U256) -> Self {
alloy_primitives::U256::from_limbs(*v.as_limbs())
}
}
}
pub type I256 = U256;
#[derive(Debug, Clone)]
pub struct Set<T: Eq + std::hash::Hash> {
items: HashSet<T>,
}
impl<T: Serialize> Serialize for Set<T>
where
T: Eq + std::hash::Hash,
{
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.items.serialize(serializer)
}
}
impl<'de, T> Deserialize<'de> for Set<T>
where
T: Deserialize<'de> + Eq + std::hash::Hash,
{
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let items = HashSet::deserialize(deserializer)?;
Ok(Set { items })
}
}
impl<T: Eq + std::hash::Hash> Set<T> {
pub fn new() -> Self {
Self {
items: HashSet::new(),
}
}
pub fn insert(&mut self, item: T) -> bool {
self.items.insert(item)
}
pub fn remove(&mut self, item: &T) -> bool {
self.items.remove(item)
}
pub fn contains(&self, item: &T) -> bool {
self.items.contains(item)
}
pub fn len(&self) -> usize {
self.items.len()
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.items.iter()
}
}
impl<T: Eq + std::hash::Hash> Default for Set<T> {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct Array<T> {
items: Vec<T>,
}
impl<T: Serialize> Serialize for Array<T> {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.items.serialize(serializer)
}
}
impl<'de, T> Deserialize<'de> for Array<T>
where
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let items = Vec::deserialize(deserializer)?;
Ok(Array { items })
}
}
impl<T> Array<T> {
pub fn new() -> Self {
Self { items: Vec::new() }
}
pub fn push(&mut self, item: T) {
self.items.push(item);
}
pub fn pop(&mut self) -> Option<T> {
self.items.pop()
}
pub fn insert(&mut self, index: usize, item: T) {
self.items.insert(index, item);
}
pub fn remove(&mut self, index: usize) -> T {
self.items.remove(index)
}
pub fn get(&self, index: usize) -> Option<&T> {
self.items.get(index)
}
pub fn len(&self) -> usize {
self.items.len()
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.items.iter()
}
}
impl<T> Default for Array<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> From<Vec<T>> for Array<T> {
fn from(items: Vec<T>) -> Self {
Self { items }
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum TypedValue {
I8(i8),
I16(i16),
I32(i32),
I64(i64),
I128(i128),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
U128(u128),
U256(U256),
I256(I256),
Bytes(Vec<u8>),
String(String),
Set(Set<String>),
Array(Array<String>),
SetI64(Set<i64>),
SetU64(Set<u64>),
SetU128(Set<u128>),
ArrayI64(Array<i64>),
ArrayU64(Array<u64>),
ArrayU128(Array<u128>),
SetBytes(Set<Vec<u8>>),
ArrayBytes(Array<Vec<u8>>),
}
impl TypedValue {
pub fn to_bytes(&self) -> Result<Vec<u8>> {
bincode::serialize(self).map_err(|e| AzothError::Serialization(e.to_string()))
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
bincode::deserialize(bytes).map_err(|e| AzothError::Serialization(e.to_string()))
}
pub fn from_json<T: Serialize>(value: &T) -> Result<Self> {
let bytes =
serde_json::to_vec(value).map_err(|e| AzothError::Serialization(e.to_string()))?;
Ok(TypedValue::Bytes(bytes))
}
pub fn to_json<T: serde::de::DeserializeOwned>(&self) -> Result<T> {
match self {
TypedValue::Bytes(bytes) => {
serde_json::from_slice(bytes).map_err(|e| AzothError::Serialization(e.to_string()))
}
_ => Err(AzothError::InvalidState(
"TypedValue must be Bytes variant for JSON deserialization".into(),
)),
}
}
pub fn as_u256(&self) -> Result<U256> {
match self {
TypedValue::U256(v) => Ok(*v),
_ => Err(AzothError::InvalidState("Not a U256".into())),
}
}
pub fn as_i64(&self) -> Result<i64> {
match self {
TypedValue::I64(v) => Ok(*v),
TypedValue::I32(v) => Ok(*v as i64),
TypedValue::I16(v) => Ok(*v as i64),
TypedValue::I8(v) => Ok(*v as i64),
_ => Err(AzothError::InvalidState("Not an i64".into())),
}
}
pub fn as_set(&self) -> Result<&Set<String>> {
match self {
TypedValue::Set(s) => Ok(s),
_ => Err(AzothError::InvalidState("Not a Set".into())),
}
}
pub fn as_set_mut(&mut self) -> Result<&mut Set<String>> {
match self {
TypedValue::Set(s) => Ok(s),
_ => Err(AzothError::InvalidState("Not a Set".into())),
}
}
pub fn as_array(&self) -> Result<&Array<String>> {
match self {
TypedValue::Array(a) => Ok(a),
_ => Err(AzothError::InvalidState("Not an Array".into())),
}
}
pub fn as_array_mut(&mut self) -> Result<&mut Array<String>> {
match self {
TypedValue::Array(a) => Ok(a),
_ => Err(AzothError::InvalidState("Not an Array".into())),
}
}
pub fn as_set_i64(&self) -> Result<&Set<i64>> {
match self {
TypedValue::SetI64(s) => Ok(s),
_ => Err(AzothError::InvalidState("Not a Set<i64>".into())),
}
}
pub fn as_set_i64_mut(&mut self) -> Result<&mut Set<i64>> {
match self {
TypedValue::SetI64(s) => Ok(s),
_ => Err(AzothError::InvalidState("Not a Set<i64>".into())),
}
}
pub fn as_set_u64(&self) -> Result<&Set<u64>> {
match self {
TypedValue::SetU64(s) => Ok(s),
_ => Err(AzothError::InvalidState("Not a Set<u64>".into())),
}
}
pub fn as_set_u64_mut(&mut self) -> Result<&mut Set<u64>> {
match self {
TypedValue::SetU64(s) => Ok(s),
_ => Err(AzothError::InvalidState("Not a Set<u64>".into())),
}
}
pub fn as_set_u128(&self) -> Result<&Set<u128>> {
match self {
TypedValue::SetU128(s) => Ok(s),
_ => Err(AzothError::InvalidState("Not a Set<u128>".into())),
}
}
pub fn as_set_u128_mut(&mut self) -> Result<&mut Set<u128>> {
match self {
TypedValue::SetU128(s) => Ok(s),
_ => Err(AzothError::InvalidState("Not a Set<u128>".into())),
}
}
pub fn as_array_i64(&self) -> Result<&Array<i64>> {
match self {
TypedValue::ArrayI64(a) => Ok(a),
_ => Err(AzothError::InvalidState("Not an Array<i64>".into())),
}
}
pub fn as_array_i64_mut(&mut self) -> Result<&mut Array<i64>> {
match self {
TypedValue::ArrayI64(a) => Ok(a),
_ => Err(AzothError::InvalidState("Not an Array<i64>".into())),
}
}
pub fn as_array_u64(&self) -> Result<&Array<u64>> {
match self {
TypedValue::ArrayU64(a) => Ok(a),
_ => Err(AzothError::InvalidState("Not an Array<u64>".into())),
}
}
pub fn as_array_u64_mut(&mut self) -> Result<&mut Array<u64>> {
match self {
TypedValue::ArrayU64(a) => Ok(a),
_ => Err(AzothError::InvalidState("Not an Array<u64>".into())),
}
}
pub fn as_array_u128(&self) -> Result<&Array<u128>> {
match self {
TypedValue::ArrayU128(a) => Ok(a),
_ => Err(AzothError::InvalidState("Not an Array<u128>".into())),
}
}
pub fn as_array_u128_mut(&mut self) -> Result<&mut Array<u128>> {
match self {
TypedValue::ArrayU128(a) => Ok(a),
_ => Err(AzothError::InvalidState("Not an Array<u128>".into())),
}
}
pub fn as_set_bytes(&self) -> Result<&Set<Vec<u8>>> {
match self {
TypedValue::SetBytes(s) => Ok(s),
_ => Err(AzothError::InvalidState("Not a Set<Vec<u8>>".into())),
}
}
pub fn as_set_bytes_mut(&mut self) -> Result<&mut Set<Vec<u8>>> {
match self {
TypedValue::SetBytes(s) => Ok(s),
_ => Err(AzothError::InvalidState("Not a Set<Vec<u8>>".into())),
}
}
pub fn as_array_bytes(&self) -> Result<&Array<Vec<u8>>> {
match self {
TypedValue::ArrayBytes(a) => Ok(a),
_ => Err(AzothError::InvalidState("Not an Array<Vec<u8>>".into())),
}
}
pub fn as_array_bytes_mut(&mut self) -> Result<&mut Array<Vec<u8>>> {
match self {
TypedValue::ArrayBytes(a) => Ok(a),
_ => Err(AzothError::InvalidState("Not an Array<Vec<u8>>".into())),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_u256_basics() {
let value = U256::from_u64(1000);
let bytes = value.to_bytes();
let decoded = U256::from_bytes(&bytes).unwrap();
assert_eq!(value, decoded);
}
#[test]
fn test_u256_checked_add() {
let a = U256::from_u64(100);
let b = U256::from_u64(200);
let result = a.checked_add(&b).unwrap();
assert_eq!(result, U256::from_u64(300));
let a = U256([u64::MAX, 0, 0, 0]);
let b = U256([1, 0, 0, 0]);
let result = a.checked_add(&b).unwrap();
assert_eq!(result, U256([0, 1, 0, 0]));
let a = U256([u64::MAX, u64::MAX, u64::MAX, u64::MAX]);
let b = U256([1, 0, 0, 0]);
assert!(a.checked_add(&b).is_none());
}
#[test]
fn test_u256_checked_sub() {
let a = U256::from_u64(300);
let b = U256::from_u64(100);
let result = a.checked_sub(&b).unwrap();
assert_eq!(result, U256::from_u64(200));
let a = U256([0, 1, 0, 0]);
let b = U256([1, 0, 0, 0]);
let result = a.checked_sub(&b).unwrap();
assert_eq!(result, U256([u64::MAX, 0, 0, 0]));
let a = U256::from_u64(100);
let b = U256::from_u64(200);
assert!(a.checked_sub(&b).is_none());
let a = U256::from_u64(100);
let b = U256::from_u64(100);
let result = a.checked_sub(&b).unwrap();
assert_eq!(result, U256::zero());
}
#[test]
fn test_set_operations() {
let mut set = Set::new();
assert!(set.insert("admin".to_string()));
assert!(set.insert("user".to_string()));
assert!(!set.insert("admin".to_string()));
assert!(set.contains(&"admin".to_string()));
assert!(!set.contains(&"guest".to_string()));
assert_eq!(set.len(), 2);
assert!(set.remove(&"admin".to_string()));
assert_eq!(set.len(), 1);
}
#[test]
fn test_array_operations() {
let mut array = Array::new();
array.push("event1".to_string());
array.push("event2".to_string());
assert_eq!(array.len(), 2);
assert_eq!(array.get(0), Some(&"event1".to_string()));
array.insert(1, "inserted".to_string());
assert_eq!(array.len(), 3);
assert_eq!(array.get(1), Some(&"inserted".to_string()));
let popped = array.pop();
assert_eq!(popped, Some("event2".to_string()));
assert_eq!(array.len(), 2);
}
#[test]
fn test_typed_value_serialization() {
let value = TypedValue::U64(12345);
let bytes = value.to_bytes().unwrap();
let decoded = TypedValue::from_bytes(&bytes).unwrap();
match decoded {
TypedValue::U64(v) => assert_eq!(v, 12345),
_ => panic!("Wrong type"),
}
}
#[test]
fn test_typed_value_set() {
let mut set = Set::new();
set.insert("role1".to_string());
set.insert("role2".to_string());
let value = TypedValue::Set(set);
let bytes = value.to_bytes().unwrap();
let decoded = TypedValue::from_bytes(&bytes).unwrap();
let decoded_set = decoded.as_set().unwrap();
assert_eq!(decoded_set.len(), 2);
assert!(decoded_set.contains(&"role1".to_string()));
}
#[test]
fn test_typed_set_u64() {
let mut set = Set::new();
set.insert(100u64);
set.insert(200u64);
set.insert(300u64);
let value = TypedValue::SetU64(set);
let bytes = value.to_bytes().unwrap();
let decoded = TypedValue::from_bytes(&bytes).unwrap();
let decoded_set = decoded.as_set_u64().unwrap();
assert_eq!(decoded_set.len(), 3);
assert!(decoded_set.contains(&100u64));
assert!(decoded_set.contains(&200u64));
assert!(!decoded_set.contains(&400u64));
}
#[test]
fn test_typed_array_i64() {
let mut array = Array::new();
array.push(-100i64);
array.push(0i64);
array.push(100i64);
let value = TypedValue::ArrayI64(array);
let bytes = value.to_bytes().unwrap();
let decoded = TypedValue::from_bytes(&bytes).unwrap();
let decoded_array = decoded.as_array_i64().unwrap();
assert_eq!(decoded_array.len(), 3);
assert_eq!(decoded_array.get(0), Some(&-100i64));
assert_eq!(decoded_array.get(1), Some(&0i64));
assert_eq!(decoded_array.get(2), Some(&100i64));
}
#[test]
fn test_typed_set_bytes() {
let mut set = Set::new();
set.insert(vec![1, 2, 3]);
set.insert(vec![4, 5, 6]);
let value = TypedValue::SetBytes(set);
let bytes = value.to_bytes().unwrap();
let decoded = TypedValue::from_bytes(&bytes).unwrap();
let decoded_set = decoded.as_set_bytes().unwrap();
assert_eq!(decoded_set.len(), 2);
assert!(decoded_set.contains(&vec![1, 2, 3]));
assert!(decoded_set.contains(&vec![4, 5, 6]));
}
#[test]
fn test_typed_array_u128() {
let mut array = Array::new();
array.push(u128::MAX);
array.push(u128::MIN);
array.push(12345u128);
let value = TypedValue::ArrayU128(array);
let bytes = value.to_bytes().unwrap();
let decoded = TypedValue::from_bytes(&bytes).unwrap();
let decoded_array = decoded.as_array_u128().unwrap();
assert_eq!(decoded_array.len(), 3);
assert_eq!(decoded_array.get(0), Some(&u128::MAX));
assert_eq!(decoded_array.get(1), Some(&u128::MIN));
assert_eq!(decoded_array.get(2), Some(&12345u128));
}
#[test]
fn test_typed_collection_type_safety() {
let set_u64 = TypedValue::SetU64(Set::new());
assert!(set_u64.as_set().is_err());
assert!(set_u64.as_set_i64().is_err());
assert!(set_u64.as_array_u64().is_err());
assert!(set_u64.as_set_u64().is_ok());
}
#[test]
fn test_json_serialization() {
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct User {
id: String,
name: String,
age: u32,
}
let user = User {
id: "user123".to_string(),
name: "Alice".to_string(),
age: 30,
};
let value = TypedValue::from_json(&user).unwrap();
match &value {
TypedValue::Bytes(_) => {}
_ => panic!("Expected Bytes variant"),
}
let decoded: User = value.to_json().unwrap();
assert_eq!(decoded, user);
}
#[test]
fn test_json_roundtrip_complex() {
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct Instance {
id: String,
state: HashMap<String, String>,
version: u64,
metadata: Option<String>,
}
let mut state = HashMap::new();
state.insert("key1".to_string(), "value1".to_string());
state.insert("key2".to_string(), "value2".to_string());
let instance = Instance {
id: "instance123".to_string(),
state,
version: 42,
metadata: Some("test metadata".to_string()),
};
let value = TypedValue::from_json(&instance).unwrap();
let decoded: Instance = value.to_json().unwrap();
assert_eq!(decoded.id, instance.id);
assert_eq!(decoded.state, instance.state);
assert_eq!(decoded.version, instance.version);
assert_eq!(decoded.metadata, instance.metadata);
}
#[test]
fn test_json_type_safety() {
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct User {
id: String,
}
#[derive(Deserialize)]
struct Post {
id: String,
title: String,
}
let user = User {
id: "user123".to_string(),
};
let value = TypedValue::from_json(&user).unwrap();
let result: Result<Post> = value.to_json();
if let Ok(post) = result {
panic!(
"Expected type mismatch error, got Post {{ id: {}, title: {} }}",
post.id, post.title
);
}
}
#[test]
fn test_json_wrong_variant() {
let value = TypedValue::I64(42);
let result: Result<String> = value.to_json();
assert!(result.is_err());
}
#[cfg(feature = "alloy")]
mod alloy_tests {
use super::*;
#[test]
fn test_alloy_u256_roundtrip() {
let alloy_val = alloy_primitives::U256::from(1_000_000u64);
let azoth_val: U256 = alloy_val.into();
let back: alloy_primitives::U256 = azoth_val.into();
assert_eq!(alloy_val, back);
}
#[test]
fn test_alloy_u256_large_value() {
let alloy_val = alloy_primitives::U256::MAX;
let azoth_val: U256 = alloy_val.into();
let back: alloy_primitives::U256 = azoth_val.into();
assert_eq!(alloy_val, back);
}
#[test]
fn test_alloy_u256_zero() {
let alloy_val = alloy_primitives::U256::ZERO;
let azoth_val: U256 = alloy_val.into();
assert_eq!(azoth_val, U256::zero());
let back: alloy_primitives::U256 = azoth_val.into();
assert_eq!(alloy_val, back);
}
}
}