hdp_primitives/task/datalake/block_sampled/
collection.rs1use std::{fmt::Display, str::FromStr};
2
3use alloy::primitives::{Address, StorageKey};
4use anyhow::{bail, Result};
5use serde::{Deserialize, Serialize};
6
7use crate::task::datalake::{DatalakeCollection, DatalakeField};
8
9use super::rlp_fields::{AccountField, HeaderField};
10
11#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12#[serde(try_from = "String")]
13pub enum BlockSampledCollection {
14 Header(HeaderField),
15 Account(Address, AccountField),
16 Storage(Address, StorageKey),
17}
18
19pub enum BlockSampledCollectionType {
20 Header,
21 Account,
22 Storage,
23}
24
25impl BlockSampledCollectionType {
26 pub fn variants() -> Vec<String> {
27 vec![
28 "HEADER".to_string(),
29 "ACCOUNT".to_string(),
30 "STORAGE".to_string(),
31 ]
32 }
33}
34
35impl FromStr for BlockSampledCollectionType {
36 type Err = anyhow::Error;
37
38 fn from_str(s: &str) -> Result<Self> {
39 match s.to_uppercase().as_str() {
40 "HEADER" => Ok(BlockSampledCollectionType::Header),
41 "ACCOUNT" => Ok(BlockSampledCollectionType::Account),
42 "STORAGE" => Ok(BlockSampledCollectionType::Storage),
43 _ => bail!("Unknown block sampled collection type"),
44 }
45 }
46}
47
48impl DatalakeCollection for BlockSampledCollection {
49 fn to_index(&self) -> u8 {
50 match self {
51 BlockSampledCollection::Header(_) => 1,
52 BlockSampledCollection::Account(..) => 2,
53 BlockSampledCollection::Storage(..) => 3,
54 }
55 }
56
57 fn serialize(&self) -> Result<Vec<u8>> {
58 let mut serialized = Vec::new();
59 match self {
60 BlockSampledCollection::Header(field) => {
61 serialized.push(1);
62 serialized.push(field.to_index());
63 }
64 BlockSampledCollection::Account(address, field) => {
65 serialized.push(2);
66 serialized.extend_from_slice(address.as_slice());
67 serialized.push(field.to_index());
68 }
69 BlockSampledCollection::Storage(address, slot) => {
70 serialized.push(3);
71 serialized.extend_from_slice(address.as_slice());
72 serialized.extend_from_slice(slot.as_ref());
73 }
74 }
75
76 Ok(serialized)
77 }
78
79 fn deserialize(serialized: &[u8]) -> Result<Self> {
80 if serialized.is_empty() {
81 bail!("Invalid block sampled collection");
82 }
83
84 match serialized[0] {
85 1 => {
86 if serialized.len() != 2 {
87 bail!("Invalid header property");
88 }
89 Ok(BlockSampledCollection::Header(HeaderField::from_index(
90 serialized[1],
91 )?))
92 }
93 2 => {
94 if serialized.len() != 22 {
95 bail!("Invalid account property");
96 }
97 let address = Address::from_slice(&serialized[1..21]);
98 Ok(BlockSampledCollection::Account(
99 address,
100 AccountField::from_index(serialized[21])?,
101 ))
102 }
103 3 => {
104 if serialized.len() != 53 {
105 bail!("Invalid storage property");
106 }
107 let address = Address::from_slice(&serialized[1..21]);
108 let slot = StorageKey::from_slice(&serialized[21..53]);
109 Ok(BlockSampledCollection::Storage(address, slot))
110 }
111 _ => bail!("Unknown block sampled collection"),
112 }
113 }
114}
115
116impl FromStr for BlockSampledCollection {
117 type Err = anyhow::Error;
118
119 fn from_str(s: &str) -> Result<Self> {
120 let parts: Vec<&str> = s.split('.').collect();
122 if !(parts.len() == 2 || parts.len() == 3) {
123 bail!("Invalid block sampled collection format");
124 }
125
126 match parts[0].to_uppercase().as_str() {
127 "HEADER" => Ok(BlockSampledCollection::Header(HeaderField::from_str(
128 parts[1].to_uppercase().as_str(),
129 )?)),
130 "ACCOUNT" => {
131 let address = Address::from_str(parts[1])?;
132 let field = AccountField::from_str(parts[2].to_uppercase().as_str())?;
133 Ok(BlockSampledCollection::Account(address, field))
134 }
135 "STORAGE" => {
136 let address = Address::from_str(parts[1])?;
137 let slot = StorageKey::from_str(parts[2])?;
138 Ok(BlockSampledCollection::Storage(address, slot))
139 }
140 _ => bail!("Unknown block sampled collection"),
141 }
142 }
143}
144
145impl TryFrom<String> for BlockSampledCollection {
146 type Error = anyhow::Error;
147
148 fn try_from(value: String) -> Result<Self> {
149 BlockSampledCollection::from_str(&value)
150 }
151}
152
153impl Display for BlockSampledCollection {
154 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
155 match self {
156 BlockSampledCollection::Header(field) => write!(f, "header.{}", field),
157 BlockSampledCollection::Account(address, field) => {
158 write!(f, "account.{}.{}", address, field)
159 }
160 BlockSampledCollection::Storage(address, slot) => {
161 write!(f, "storage.{}.{}", address, slot)
162 }
163 }
164 }
165}