1use serde::{Deserialize, Serialize};
21
22#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
24pub enum FieldType {
25 U8,
26 U16,
27 U32,
28 U64,
29 U128,
30 I64,
31 Bool,
32 Bytes(usize),
34 VarBytes,
36 Address,
38 Hash,
40}
41
42impl FieldType {
43 pub fn fixed_size(&self) -> Option<usize> {
45 match self {
46 FieldType::U8 => Some(1),
47 FieldType::U16 => Some(2),
48 FieldType::U32 => Some(4),
49 FieldType::U64 => Some(8),
50 FieldType::U128 => Some(16),
51 FieldType::I64 => Some(8),
52 FieldType::Bool => Some(1),
53 FieldType::Bytes(n) => Some(*n),
54 FieldType::Address => Some(32),
55 FieldType::Hash => Some(32),
56 FieldType::VarBytes => None,
57 }
58 }
59
60 pub fn type_name(&self) -> &'static str {
61 match self {
62 FieldType::U8 => "u8",
63 FieldType::U16 => "u16",
64 FieldType::U32 => "u32",
65 FieldType::U64 => "u64",
66 FieldType::U128 => "u128",
67 FieldType::I64 => "i64",
68 FieldType::Bool => "bool",
69 FieldType::Bytes(_) => "bytes",
70 FieldType::VarBytes => "varbytes",
71 FieldType::Address => "address",
72 FieldType::Hash => "hash",
73 }
74 }
75}
76
77#[derive(Debug, Clone, Serialize, Deserialize)]
79pub struct Field {
80 pub name: String,
81 pub field_type: FieldType,
82 pub is_key: bool,
85 pub indexed: bool,
87}
88
89impl Field {
90 pub fn key(name: impl Into<String>, field_type: FieldType) -> Self {
91 Self {
92 name: name.into(),
93 field_type,
94 is_key: true,
95 indexed: false,
96 }
97 }
98
99 pub fn value(name: impl Into<String>, field_type: FieldType) -> Self {
100 Self {
101 name: name.into(),
102 field_type,
103 is_key: false,
104 indexed: false,
105 }
106 }
107
108 pub fn indexed_value(name: impl Into<String>, field_type: FieldType) -> Self {
109 Self {
110 name: name.into(),
111 field_type,
112 is_key: false,
113 indexed: true,
114 }
115 }
116}
117
118#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
122pub enum FieldValue {
123 U8(u8),
124 U16(u16),
125 U32(u32),
126 U64(u64),
127 U128(u128),
128 I64(i64),
129 Bool(bool),
130 Bytes(Vec<u8>),
132 Null,
133}
134
135impl FieldValue {
136 pub fn type_name(&self) -> &'static str {
137 match self {
138 FieldValue::U8(_) => "u8",
139 FieldValue::U16(_) => "u16",
140 FieldValue::U32(_) => "u32",
141 FieldValue::U64(_) => "u64",
142 FieldValue::U128(_) => "u128",
143 FieldValue::I64(_) => "i64",
144 FieldValue::Bool(_) => "bool",
145 FieldValue::Bytes(_) => "bytes",
146 FieldValue::Null => "null",
147 }
148 }
149
150 pub fn as_u64(&self) -> Option<u64> {
151 match self {
152 FieldValue::U8(v) => Some(*v as u64),
153 FieldValue::U16(v) => Some(*v as u64),
154 FieldValue::U32(v) => Some(*v as u64),
155 FieldValue::U64(v) => Some(*v),
156 _ => None,
157 }
158 }
159
160 pub fn as_u128(&self) -> Option<u128> {
161 match self {
162 FieldValue::U128(v) => Some(*v),
163 other => other.as_u64().map(|v| v as u128),
164 }
165 }
166
167 pub fn as_bytes(&self) -> Option<&[u8]> {
168 match self {
169 FieldValue::Bytes(v) => Some(v.as_slice()),
170 _ => None,
171 }
172 }
173}
174
175#[derive(Debug, Clone, Serialize, Deserialize)]
180pub struct Schema {
181 pub name: String,
182 pub fields: Vec<Field>,
183}
184
185impl Schema {
186 pub fn new(name: impl Into<String>, fields: Vec<Field>) -> Self {
187 Self {
188 name: name.into(),
189 fields,
190 }
191 }
192
193 pub fn field(&self, name: &str) -> Option<(usize, &Field)> {
194 self.fields.iter().enumerate().find(|(_, f)| f.name == name)
195 }
196
197 pub fn key_fields(&self) -> Vec<(usize, &Field)> {
198 self.fields
199 .iter()
200 .enumerate()
201 .filter(|(_, f)| f.is_key)
202 .collect()
203 }
204
205 pub fn indexed_fields(&self) -> Vec<(usize, &Field)> {
206 self.fields
207 .iter()
208 .enumerate()
209 .filter(|(_, f)| f.indexed)
210 .collect()
211 }
212
213 pub fn value_fields(&self) -> Vec<(usize, &Field)> {
214 self.fields
215 .iter()
216 .enumerate()
217 .filter(|(_, f)| !f.is_key)
218 .collect()
219 }
220}
221
222#[derive(Debug, Clone, PartialEq)]
227pub struct Record {
228 pub values: Vec<FieldValue>,
229}
230
231impl Record {
232 pub fn new(values: Vec<FieldValue>) -> Self {
233 Self { values }
234 }
235
236 pub fn get(&self, idx: usize) -> Option<&FieldValue> {
237 self.values.get(idx)
238 }
239
240 pub fn get_by_name<'a>(&'a self, schema: &Schema, name: &str) -> Option<&'a FieldValue> {
241 let (idx, _) = schema.field(name)?;
242 self.values.get(idx)
243 }
244
245 pub fn validate(&self, schema: &Schema) -> Result<(), crate::error::RelError> {
247 if self.values.len() != schema.fields.len() {
248 return Err(crate::error::RelError::Schema(format!(
249 "record has {} values, schema '{}' expects {}",
250 self.values.len(),
251 schema.name,
252 schema.fields.len()
253 )));
254 }
255 for (field, value) in schema.fields.iter().zip(self.values.iter()) {
256 let ok = match (&field.field_type, value) {
257 (FieldType::U8, FieldValue::U8(_)) => true,
258 (FieldType::U16, FieldValue::U16(_)) => true,
259 (FieldType::U32, FieldValue::U32(_)) => true,
260 (FieldType::U64, FieldValue::U64(_)) => true,
261 (FieldType::U128, FieldValue::U128(_)) => true,
262 (FieldType::I64, FieldValue::I64(_)) => true,
263 (FieldType::Bool, FieldValue::Bool(_)) => true,
264 (FieldType::Bytes(n), FieldValue::Bytes(b)) => b.len() == *n,
265 (FieldType::VarBytes, FieldValue::Bytes(_)) => true,
266 (FieldType::Address, FieldValue::Bytes(b)) => b.len() == 32,
267 (FieldType::Hash, FieldValue::Bytes(b)) => b.len() == 32,
268 (_, FieldValue::Null) => true, _ => false,
270 };
271 if !ok {
272 return Err(crate::error::RelError::TypeMismatch {
273 field: field.name.clone(),
274 expected: field.field_type.type_name().to_string(),
275 got: value.type_name().to_string(),
276 });
277 }
278 }
279 Ok(())
280 }
281}