1use std::any::type_name;
2
3use crypto_bigint::{Encoding, U256};
4use num_traits::ToPrimitive;
5use serde::{Deserialize, Serialize};
6use serde_json::{json, Value as JsonValue};
7use starknet::core::types::Felt;
8use strum::IntoEnumIterator;
9use strum_macros::{AsRefStr, Display, EnumIter, EnumString};
10
11use super::primitive_conversion::try_from_felt;
12
13#[derive(
14 AsRefStr,
15 Display,
16 EnumIter,
17 EnumString,
18 Copy,
19 Clone,
20 Debug,
21 Serialize,
22 Deserialize,
23 PartialEq,
24 Hash,
25 Eq,
26 PartialOrd,
27 Ord,
28)]
29#[serde(tag = "scalar_type", content = "value")]
30#[strum(serialize_all = "lowercase")]
31#[serde(rename_all = "lowercase")]
32pub enum Primitive {
33 I8(Option<i8>),
34 I16(Option<i16>),
35 I32(Option<i32>),
36 I64(Option<i64>),
37 I128(Option<i128>),
38 U8(Option<u8>),
39 U16(Option<u16>),
40 U32(Option<u32>),
41 U64(Option<u64>),
42 U128(Option<u128>),
43 U256(Option<U256>),
44 Bool(Option<bool>),
45 Felt252(Option<Felt>),
46 #[strum(serialize = "ClassHash")]
47 ClassHash(Option<Felt>),
48 #[strum(serialize = "ContractAddress")]
49 ContractAddress(Option<Felt>),
50 #[strum(serialize = "EthAddress")]
51 EthAddress(Option<Felt>),
52}
53
54#[derive(Debug, thiserror::Error)]
55pub enum PrimitiveError {
56 #[error("Invalid enum selector `{actual_selector}`")]
57 InvalidEnumSelector {
58 actual_selector: u8,
60 },
61
62 #[error("Value must have at least one FieldElement")]
63 MissingFieldElement,
64 #[error("Not enough FieldElements for U256")]
65 NotEnoughFieldElements,
66 #[error("Unsupported CairoType for SQL formatting")]
67 UnsupportedType,
68 #[error("Invalid byte length: {0}. expected {1}")]
69 InvalidByteLength(usize, usize),
70 #[error("Set value type mismatch")]
71 TypeMismatch,
72 #[error("Felt value ({value:#x}) out of range for {r#type}")]
73 ValueOutOfRange { value: Felt, r#type: &'static str },
74 #[error("Invalid SQL value format: {0}")]
75 InvalidSqlValue(String),
76 #[error("Invalid JSON value format for type {r#type}: {value}")]
77 InvalidJsonValue { r#type: &'static str, value: String },
78 #[error("JSON number out of range for {r#type}: {value}")]
79 JsonNumberOutOfRange { r#type: &'static str, value: String },
80 #[error(transparent)]
81 CairoSerde(#[from] cainome::cairo_serde::Error),
82 #[error(transparent)]
83 FromUtf8Error(#[from] std::string::FromUtf8Error),
84 #[error(transparent)]
85 FeltFromFeltError(#[from] crate::primitive_conversion::PrimitiveFromFeltError),
86}
87
88#[derive(AsRefStr, Debug, Display, EnumString, PartialEq)]
89#[strum(serialize_all = "UPPERCASE")]
90pub enum SqlType {
91 Integer,
92 Text,
93}
94
95macro_rules! set_primitive {
97 ($method_name:ident, $variant:ident, $type:ty) => {
98 pub fn $method_name(&mut self, value: Option<$type>) -> Result<(), PrimitiveError> {
100 match self {
101 Primitive::$variant(_) => {
102 *self = Primitive::$variant(value);
103 Ok(())
104 }
105 _ => Err(PrimitiveError::TypeMismatch),
106 }
107 }
108 };
109}
110
111macro_rules! as_primitive {
113 ($method_name:ident, $variant:ident, $type:ty) => {
114 pub fn $method_name(&self) -> Option<$type> {
117 match self {
118 Primitive::$variant(value) => *value,
119 _ => None,
120 }
121 }
122 };
123}
124
125impl Primitive {
126 as_primitive!(as_i8, I8, i8);
127 as_primitive!(as_i16, I16, i16);
128 as_primitive!(as_i32, I32, i32);
129 as_primitive!(as_i64, I64, i64);
130 as_primitive!(as_i128, I128, i128);
131 as_primitive!(as_u8, U8, u8);
132 as_primitive!(as_u16, U16, u16);
133 as_primitive!(as_u32, U32, u32);
134 as_primitive!(as_u64, U64, u64);
135 as_primitive!(as_u128, U128, u128);
136 as_primitive!(as_u256, U256, U256);
137 as_primitive!(as_bool, Bool, bool);
138 as_primitive!(as_felt252, Felt252, Felt);
139 as_primitive!(as_class_hash, ClassHash, Felt);
140 as_primitive!(as_contract_address, ContractAddress, Felt);
141 as_primitive!(as_eth_address, EthAddress, Felt);
142
143 set_primitive!(set_i8, I8, i8);
144 set_primitive!(set_i16, I16, i16);
145 set_primitive!(set_i32, I32, i32);
146 set_primitive!(set_i64, I64, i64);
147 set_primitive!(set_i128, I128, i128);
148 set_primitive!(set_u8, U8, u8);
149 set_primitive!(set_u16, U16, u16);
150 set_primitive!(set_u32, U32, u32);
151 set_primitive!(set_u64, U64, u64);
152 set_primitive!(set_u128, U128, u128);
153 set_primitive!(set_u256, U256, U256);
154 set_primitive!(set_bool, Bool, bool);
155 set_primitive!(set_felt252, Felt252, Felt);
156 set_primitive!(set_class_hash, ClassHash, Felt);
157 set_primitive!(set_contract_address, ContractAddress, Felt);
158 set_primitive!(set_eth_address, EthAddress, Felt);
159
160 pub fn to_numeric(&self) -> usize {
161 match self {
162 Primitive::Bool(_) => 0,
163 Primitive::U8(_) => 1,
164 Primitive::U16(_) => 2,
165 Primitive::U32(_) => 3,
166 Primitive::U64(_) => 4,
167 Primitive::U128(_) => 5,
168 Primitive::U256(_) => 6,
169 Primitive::I8(_) => 7,
170 Primitive::I16(_) => 8,
171 Primitive::I32(_) => 9,
172 Primitive::I64(_) => 10,
173 Primitive::I128(_) => 11,
174 Primitive::Felt252(_) => 12,
175 Primitive::ClassHash(_) => 13,
176 Primitive::ContractAddress(_) => 14,
177 Primitive::EthAddress(_) => 15,
178 }
179 }
180
181 pub fn from_numeric(value: usize) -> Option<Self> {
182 Self::iter().nth(value)
183 }
184
185 pub fn to_sql_type(&self) -> SqlType {
186 match self {
187 Primitive::I8(_)
189 | Primitive::I16(_)
190 | Primitive::I32(_)
191 | Primitive::I64(_)
192 | Primitive::U8(_)
193 | Primitive::U16(_)
194 | Primitive::U32(_)
195 | Primitive::Bool(_) => SqlType::Integer,
196
197 Primitive::U64(_)
199 | Primitive::I128(_)
200 | Primitive::U128(_)
201 | Primitive::U256(_)
202 | Primitive::ContractAddress(_)
203 | Primitive::ClassHash(_)
204 | Primitive::Felt252(_)
205 | Primitive::EthAddress(_) => SqlType::Text,
206 }
207 }
208
209 pub fn to_sql_value(&self) -> String {
210 match self {
211 Primitive::I8(v) => v.unwrap_or_default().to_string(),
213 Primitive::I16(v) => v.unwrap_or_default().to_string(),
214 Primitive::I32(v) => v.unwrap_or_default().to_string(),
215 Primitive::I64(v) => v.unwrap_or_default().to_string(),
216 Primitive::U8(v) => v.unwrap_or_default().to_string(),
217 Primitive::U16(v) => v.unwrap_or_default().to_string(),
218 Primitive::U32(v) => v.unwrap_or_default().to_string(),
219 Primitive::Bool(v) => (v.unwrap_or_default() as i32).to_string(),
220
221 Primitive::I128(v) => format!("0x{:032x}", v.unwrap_or_default()),
223 Primitive::U64(v) => format!("0x{:016x}", v.unwrap_or_default()),
224 Primitive::U128(v) => format!("0x{:032x}", v.unwrap_or_default()),
225 Primitive::U256(v) => format!("0x{:064x}", v.unwrap_or_default()),
226 Primitive::ContractAddress(v) => format!("0x{:064x}", v.unwrap_or_default()),
227 Primitive::ClassHash(v) => format!("0x{:064x}", v.unwrap_or_default()),
228 Primitive::Felt252(v) => format!("0x{:064x}", v.unwrap_or_default()),
229 Primitive::EthAddress(v) => format!("0x{:040x}", v.unwrap_or_default()),
230 }
231 }
232
233 pub fn from_sql_value(&mut self, value: &str) -> Result<(), PrimitiveError> {
234 match self {
235 Primitive::I8(ref mut inner) => {
237 *inner = Some(
238 value
239 .parse()
240 .map_err(|_| PrimitiveError::InvalidSqlValue(value.to_string()))?,
241 );
242 }
243 Primitive::I16(ref mut inner) => {
244 *inner = Some(
245 value
246 .parse()
247 .map_err(|_| PrimitiveError::InvalidSqlValue(value.to_string()))?,
248 );
249 }
250 Primitive::I32(ref mut inner) => {
251 *inner = Some(
252 value
253 .parse()
254 .map_err(|_| PrimitiveError::InvalidSqlValue(value.to_string()))?,
255 );
256 }
257 Primitive::I64(ref mut inner) => {
258 *inner = Some(
259 value
260 .parse()
261 .map_err(|_| PrimitiveError::InvalidSqlValue(value.to_string()))?,
262 );
263 }
264 Primitive::U8(ref mut inner) => {
265 *inner = Some(
266 value
267 .parse()
268 .map_err(|_| PrimitiveError::InvalidSqlValue(value.to_string()))?,
269 );
270 }
271 Primitive::U16(ref mut inner) => {
272 *inner = Some(
273 value
274 .parse()
275 .map_err(|_| PrimitiveError::InvalidSqlValue(value.to_string()))?,
276 );
277 }
278 Primitive::U32(ref mut inner) => {
279 *inner = Some(
280 value
281 .parse()
282 .map_err(|_| PrimitiveError::InvalidSqlValue(value.to_string()))?,
283 );
284 }
285 Primitive::Bool(ref mut inner) => {
286 let int_val: i32 = value
287 .parse()
288 .map_err(|_| PrimitiveError::InvalidSqlValue(value.to_string()))?;
289 *inner = Some(int_val != 0);
290 }
291
292 Primitive::I128(ref mut inner) => {
294 let hex_str = value
295 .strip_prefix("0x")
296 .ok_or_else(|| PrimitiveError::InvalidSqlValue(value.to_string()))?;
297
298 let as_u128 = u128::from_str_radix(hex_str, 16)
300 .map_err(|_| PrimitiveError::InvalidSqlValue(value.to_string()))?;
301 *inner = Some(as_u128 as i128);
302 }
303
304 Primitive::U64(ref mut inner) => {
306 if let Some(hex_str) = value.strip_prefix("0x") {
308 *inner = Some(
309 u64::from_str_radix(hex_str, 16)
310 .map_err(|_| PrimitiveError::InvalidSqlValue(value.to_string()))?,
311 );
312 } else {
313 *inner = Some(
315 value
316 .parse()
317 .map_err(|_| PrimitiveError::InvalidSqlValue(value.to_string()))?,
318 );
319 }
320 }
321 Primitive::U128(ref mut inner) => {
322 if let Some(hex_str) = value.strip_prefix("0x") {
324 *inner = Some(
325 u128::from_str_radix(hex_str, 16)
326 .map_err(|_| PrimitiveError::InvalidSqlValue(value.to_string()))?,
327 );
328 } else {
329 *inner = Some(
331 value
332 .parse()
333 .map_err(|_| PrimitiveError::InvalidSqlValue(value.to_string()))?,
334 );
335 }
336 }
337 Primitive::U256(ref mut inner) => {
338 let hex_str = value
339 .strip_prefix("0x")
340 .ok_or_else(|| PrimitiveError::InvalidSqlValue(value.to_string()))?;
341 let padded_hex = format!("{:0>64}", hex_str);
343 *inner = Some(U256::from_be_hex(&padded_hex));
344 }
345 Primitive::ContractAddress(ref mut inner) => {
346 let hex_str = value
347 .strip_prefix("0x")
348 .ok_or_else(|| PrimitiveError::InvalidSqlValue(value.to_string()))?;
349 *inner = Some(
350 Felt::from_hex(hex_str)
351 .map_err(|_| PrimitiveError::InvalidSqlValue(value.to_string()))?,
352 );
353 }
354 Primitive::ClassHash(ref mut inner) => {
355 let hex_str = value
356 .strip_prefix("0x")
357 .ok_or_else(|| PrimitiveError::InvalidSqlValue(value.to_string()))?;
358 *inner = Some(
359 Felt::from_hex(hex_str)
360 .map_err(|_| PrimitiveError::InvalidSqlValue(value.to_string()))?,
361 );
362 }
363 Primitive::Felt252(ref mut inner) => {
364 let hex_str = value
365 .strip_prefix("0x")
366 .ok_or_else(|| PrimitiveError::InvalidSqlValue(value.to_string()))?;
367 *inner = Some(
368 Felt::from_hex(hex_str)
369 .map_err(|_| PrimitiveError::InvalidSqlValue(value.to_string()))?,
370 );
371 }
372 Primitive::EthAddress(ref mut inner) => {
373 let hex_str = value
374 .strip_prefix("0x")
375 .ok_or_else(|| PrimitiveError::InvalidSqlValue(value.to_string()))?;
376 *inner = Some(
377 Felt::from_hex(hex_str)
378 .map_err(|_| PrimitiveError::InvalidSqlValue(value.to_string()))?,
379 );
380 }
381 }
382 Ok(())
383 }
384
385 pub fn to_json_value(&self) -> Result<JsonValue, PrimitiveError> {
387 match self {
388 Primitive::I8(Some(v)) => Ok(json!(*v)),
390 Primitive::I16(Some(v)) => Ok(json!(*v)),
391 Primitive::I32(Some(v)) => Ok(json!(*v)),
392 Primitive::U8(Some(v)) => Ok(json!(*v)),
393 Primitive::U16(Some(v)) => Ok(json!(*v)),
394 Primitive::U32(Some(v)) => Ok(json!(*v)),
395 Primitive::Bool(Some(v)) => Ok(json!(*v)),
396
397 Primitive::I64(Some(v)) => Ok(json!(v.to_string())),
399 Primitive::I128(Some(v)) => Ok(json!(v.to_string())),
400 Primitive::U64(Some(v)) => Ok(json!(v.to_string())),
401 Primitive::U128(Some(v)) => Ok(json!(v.to_string())),
402
403 Primitive::U256(Some(v)) => Ok(json!(format!("0x{:064x}", v))),
405
406 Primitive::ContractAddress(Some(v)) => Ok(json!(format!("0x{:064x}", v))),
408 Primitive::ClassHash(Some(v)) => Ok(json!(format!("0x{:064x}", v))),
409 Primitive::Felt252(Some(v)) => Ok(json!(format!("0x{:064x}", v))),
410 Primitive::EthAddress(Some(v)) => Ok(json!(format!("0x{:040x}", v))),
411
412 _ => Err(PrimitiveError::MissingFieldElement),
414 }
415 }
416
417 pub fn from_json_value(&mut self, value: JsonValue) -> Result<(), PrimitiveError> {
419 match (self, value) {
420 (Primitive::Bool(ref mut inner), JsonValue::Bool(b)) => {
422 *inner = Some(b);
423 }
424 (Primitive::Bool(ref mut inner), JsonValue::Number(n)) => {
425 if let Some(i) = n.as_i64() {
426 *inner = Some(i != 0);
427 } else {
428 return Err(PrimitiveError::InvalidJsonValue {
429 r#type: "Bool",
430 value: n.to_string(),
431 });
432 }
433 }
434
435 (Primitive::I8(ref mut inner), JsonValue::Number(n)) => {
437 if let Some(i) = n.as_i64() {
438 if i >= i8::MIN as i64 && i <= i8::MAX as i64 {
439 *inner = Some(i as i8);
440 } else {
441 return Err(PrimitiveError::JsonNumberOutOfRange {
442 r#type: "I8",
443 value: i.to_string(),
444 });
445 }
446 } else {
447 return Err(PrimitiveError::InvalidJsonValue {
448 r#type: "I8",
449 value: n.to_string(),
450 });
451 }
452 }
453 (Primitive::I16(ref mut inner), JsonValue::Number(n)) => {
454 if let Some(i) = n.as_i64() {
455 if i >= i16::MIN as i64 && i <= i16::MAX as i64 {
456 *inner = Some(i as i16);
457 } else {
458 return Err(PrimitiveError::JsonNumberOutOfRange {
459 r#type: "I16",
460 value: i.to_string(),
461 });
462 }
463 } else {
464 return Err(PrimitiveError::InvalidJsonValue {
465 r#type: "I16",
466 value: n.to_string(),
467 });
468 }
469 }
470 (Primitive::I32(ref mut inner), JsonValue::Number(n)) => {
471 if let Some(i) = n.as_i64() {
472 if i >= i32::MIN as i64 && i <= i32::MAX as i64 {
473 *inner = Some(i as i32);
474 } else {
475 return Err(PrimitiveError::JsonNumberOutOfRange {
476 r#type: "I32",
477 value: i.to_string(),
478 });
479 }
480 } else {
481 return Err(PrimitiveError::InvalidJsonValue {
482 r#type: "I32",
483 value: n.to_string(),
484 });
485 }
486 }
487
488 (Primitive::U8(ref mut inner), JsonValue::Number(n)) => {
490 if let Some(u) = n.as_u64() {
491 if u <= u8::MAX as u64 {
492 *inner = Some(u as u8);
493 } else {
494 return Err(PrimitiveError::JsonNumberOutOfRange {
495 r#type: "U8",
496 value: u.to_string(),
497 });
498 }
499 } else {
500 return Err(PrimitiveError::InvalidJsonValue {
501 r#type: "U8",
502 value: n.to_string(),
503 });
504 }
505 }
506 (Primitive::U16(ref mut inner), JsonValue::Number(n)) => {
507 if let Some(u) = n.as_u64() {
508 if u <= u16::MAX as u64 {
509 *inner = Some(u as u16);
510 } else {
511 return Err(PrimitiveError::JsonNumberOutOfRange {
512 r#type: "U16",
513 value: u.to_string(),
514 });
515 }
516 } else {
517 return Err(PrimitiveError::InvalidJsonValue {
518 r#type: "U16",
519 value: n.to_string(),
520 });
521 }
522 }
523 (Primitive::U32(ref mut inner), JsonValue::Number(n)) => {
524 if let Some(u) = n.as_u64() {
525 if u <= u32::MAX as u64 {
526 *inner = Some(u as u32);
527 } else {
528 return Err(PrimitiveError::JsonNumberOutOfRange {
529 r#type: "U32",
530 value: u.to_string(),
531 });
532 }
533 } else {
534 return Err(PrimitiveError::InvalidJsonValue {
535 r#type: "U32",
536 value: n.to_string(),
537 });
538 }
539 }
540
541 (Primitive::I64(ref mut inner), JsonValue::String(s)) => {
543 *inner =
544 Some(s.parse().map_err(|_| PrimitiveError::InvalidJsonValue {
545 r#type: "I64",
546 value: s,
547 })?);
548 }
549 (Primitive::I64(ref mut inner), JsonValue::Number(n)) => {
550 if let Some(i) = n.as_i64() {
551 *inner = Some(i);
552 } else {
553 return Err(PrimitiveError::InvalidJsonValue {
554 r#type: "I64",
555 value: n.to_string(),
556 });
557 }
558 }
559
560 (primitive, JsonValue::String(s)) => {
562 match primitive {
563 Primitive::I128(ref mut inner) => {
564 if let Some(hex_str) = s.strip_prefix("0x") {
566 let as_u128 = u128::from_str_radix(hex_str, 16).map_err(|_| {
569 PrimitiveError::InvalidJsonValue { r#type: "I128", value: s }
570 })?;
571 *inner = Some(as_u128 as i128);
572 } else {
573 *inner = Some(s.parse().map_err(|_| {
574 PrimitiveError::InvalidJsonValue { r#type: "I128", value: s }
575 })?);
576 }
577 }
578 Primitive::U64(ref mut inner) => {
579 if let Some(hex_str) = s.strip_prefix("0x") {
581 *inner = Some(u64::from_str_radix(hex_str, 16).map_err(|_| {
582 PrimitiveError::InvalidJsonValue { r#type: "U64", value: s }
583 })?);
584 } else {
585 *inner = Some(s.parse().map_err(|_| {
586 PrimitiveError::InvalidJsonValue { r#type: "U64", value: s }
587 })?);
588 }
589 }
590 Primitive::U128(ref mut inner) => {
591 if let Some(hex_str) = s.strip_prefix("0x") {
593 *inner = Some(u128::from_str_radix(hex_str, 16).map_err(|_| {
594 PrimitiveError::InvalidJsonValue { r#type: "U128", value: s }
595 })?);
596 } else {
597 *inner = Some(s.parse().map_err(|_| {
598 PrimitiveError::InvalidJsonValue { r#type: "U128", value: s }
599 })?);
600 }
601 }
602 Primitive::U256(ref mut inner) => {
603 let hex_str = s.strip_prefix("0x").unwrap_or(&s);
605 let padded_hex = format!("{:0>64}", hex_str);
607 *inner = Some(U256::from_be_hex(&padded_hex));
608 }
609 Primitive::ContractAddress(ref mut inner) => {
610 let hex_str = s.strip_prefix("0x").unwrap_or(&s);
611 *inner = Some(Felt::from_hex(hex_str).map_err(|_| {
612 PrimitiveError::InvalidJsonValue { r#type: "ContractAddress", value: s }
613 })?);
614 }
615 Primitive::ClassHash(ref mut inner) => {
616 let hex_str = s.strip_prefix("0x").unwrap_or(&s);
617 *inner = Some(Felt::from_hex(hex_str).map_err(|_| {
618 PrimitiveError::InvalidJsonValue { r#type: "ClassHash", value: s }
619 })?);
620 }
621 Primitive::Felt252(ref mut inner) => {
622 let hex_str = s.strip_prefix("0x").unwrap_or(&s);
623 *inner = Some(Felt::from_hex(hex_str).map_err(|_| {
624 PrimitiveError::InvalidJsonValue { r#type: "Felt252", value: s }
625 })?);
626 }
627 Primitive::EthAddress(ref mut inner) => {
628 let hex_str = s.strip_prefix("0x").unwrap_or(&s);
629 *inner = Some(Felt::from_hex(hex_str).map_err(|_| {
630 PrimitiveError::InvalidJsonValue { r#type: "EthAddress", value: s }
631 })?);
632 }
633 _ => {
634 return Err(PrimitiveError::InvalidJsonValue {
635 r#type: "Unknown",
636 value: s,
637 });
638 }
639 }
640 }
641
642 _ => {
643 return Err(PrimitiveError::TypeMismatch);
644 }
645 }
646 Ok(())
647 }
648
649 pub fn deserialize(&mut self, felts: &mut Vec<Felt>) -> Result<(), PrimitiveError> {
650 if felts.is_empty() {
651 return Err(PrimitiveError::MissingFieldElement);
652 }
653
654 match self {
655 Primitive::I8(ref mut value) => {
656 let felt = felts.remove(0);
657 *value = Some(try_from_felt::<i8>(felt).map_err(|_| {
658 PrimitiveError::ValueOutOfRange { r#type: type_name::<i8>(), value: felt }
659 })?);
660 }
661
662 Primitive::I16(ref mut value) => {
663 let felt = felts.remove(0);
664 *value = Some(try_from_felt::<i16>(felt).map_err(|_| {
665 PrimitiveError::ValueOutOfRange { r#type: type_name::<i16>(), value: felt }
666 })?);
667 }
668
669 Primitive::I32(ref mut value) => {
670 let felt = felts.remove(0);
671 *value = Some(try_from_felt::<i32>(felt).map_err(|_| {
672 PrimitiveError::ValueOutOfRange { r#type: type_name::<i32>(), value: felt }
673 })?);
674 }
675
676 Primitive::I64(ref mut value) => {
677 let felt = felts.remove(0);
678 *value = Some(try_from_felt::<i64>(felt).map_err(|_| {
679 PrimitiveError::ValueOutOfRange { r#type: type_name::<i64>(), value: felt }
680 })?);
681 }
682
683 Primitive::I128(ref mut value) => {
684 let felt = felts.remove(0);
685 *value = Some(try_from_felt::<i128>(felt).map_err(|_| {
686 PrimitiveError::ValueOutOfRange { r#type: type_name::<i128>(), value: felt }
687 })?);
688 }
689
690 Primitive::U8(ref mut value) => {
691 let felt = felts.remove(0);
692 *value = Some(felt.to_u8().ok_or_else(|| PrimitiveError::ValueOutOfRange {
693 r#type: type_name::<u8>(),
694 value: felt,
695 })?);
696 }
697
698 Primitive::U16(ref mut value) => {
699 let felt = felts.remove(0);
700 *value = Some(felt.to_u16().ok_or_else(|| PrimitiveError::ValueOutOfRange {
701 r#type: type_name::<u16>(),
702 value: felt,
703 })?);
704 }
705
706 Primitive::U32(ref mut value) => {
707 let felt = felts.remove(0);
708 *value = Some(felt.to_u32().ok_or_else(|| PrimitiveError::ValueOutOfRange {
709 r#type: type_name::<u32>(),
710 value: felt,
711 })?);
712 }
713
714 Primitive::U64(ref mut value) => {
715 let felt = felts.remove(0);
716 *value = Some(felt.to_u64().ok_or_else(|| PrimitiveError::ValueOutOfRange {
717 r#type: type_name::<u64>(),
718 value: felt,
719 })?);
720 }
721
722 Primitive::U128(ref mut value) => {
723 let felt = felts.remove(0);
724 *value = Some(felt.to_u128().ok_or_else(|| PrimitiveError::ValueOutOfRange {
725 r#type: type_name::<u128>(),
726 value: felt,
727 })?);
728 }
729
730 Primitive::U256(ref mut value) => {
731 if felts.len() < 2 {
732 return Err(PrimitiveError::NotEnoughFieldElements);
733 }
734 let value0 = felts.remove(0);
735 let value1 = felts.remove(0);
736 let value0_bytes = value0.to_bytes_be();
737 let value1_bytes = value1.to_bytes_be();
738 let mut bytes = [0u8; 32];
739 bytes[16..].copy_from_slice(&value0_bytes[16..]);
740 bytes[..16].copy_from_slice(&value1_bytes[16..]);
741 *value = Some(U256::from_be_bytes(bytes));
742 }
743
744 Primitive::Bool(ref mut value) => {
745 let raw = felts.remove(0);
746 *value = Some(raw == Felt::ONE);
747 }
748
749 Primitive::ContractAddress(ref mut value) => {
750 *value = Some(felts.remove(0));
751 }
752
753 Primitive::ClassHash(ref mut value) => {
754 *value = Some(felts.remove(0));
755 }
756
757 Primitive::Felt252(ref mut value) => {
758 *value = Some(felts.remove(0));
759 }
760
761 Primitive::EthAddress(ref mut value) => {
762 *value = Some(felts.remove(0));
763 }
764 }
765
766 Ok(())
767 }
768
769 pub fn serialize(&self) -> Result<Vec<Felt>, PrimitiveError> {
770 match self {
771 Primitive::I8(value) => value
772 .map(|v| Ok(vec![Felt::from(v)]))
773 .unwrap_or(Err(PrimitiveError::MissingFieldElement)),
774 Primitive::I16(value) => value
775 .map(|v| Ok(vec![Felt::from(v)]))
776 .unwrap_or(Err(PrimitiveError::MissingFieldElement)),
777 Primitive::I32(value) => value
778 .map(|v| Ok(vec![Felt::from(v)]))
779 .unwrap_or(Err(PrimitiveError::MissingFieldElement)),
780 Primitive::I64(value) => value
781 .map(|v| Ok(vec![Felt::from(v)]))
782 .unwrap_or(Err(PrimitiveError::MissingFieldElement)),
783 Primitive::I128(value) => value
784 .map(|v| Ok(vec![Felt::from(v)]))
785 .unwrap_or(Err(PrimitiveError::MissingFieldElement)),
786 Primitive::U8(value) => value
787 .map(|v| Ok(vec![Felt::from(v)]))
788 .unwrap_or(Err(PrimitiveError::MissingFieldElement)),
789 Primitive::U16(value) => value
790 .map(|v| Ok(vec![Felt::from(v)]))
791 .unwrap_or(Err(PrimitiveError::MissingFieldElement)),
792 Primitive::U32(value) => value
793 .map(|v| Ok(vec![Felt::from(v)]))
794 .unwrap_or(Err(PrimitiveError::MissingFieldElement)),
795 Primitive::U64(value) => value
796 .map(|v| Ok(vec![Felt::from(v)]))
797 .unwrap_or(Err(PrimitiveError::MissingFieldElement)),
798 Primitive::U128(value) => value
799 .map(|v| Ok(vec![Felt::from(v)]))
800 .unwrap_or(Err(PrimitiveError::MissingFieldElement)),
801 Primitive::U256(value) => value
802 .map(|v| {
803 let bytes: [u8; 32] = v.to_be_bytes();
804 let value0_slice = &bytes[16..];
805 let value1_slice = &bytes[..16];
806 let mut value0_array = [0u8; 32];
807 let mut value1_array = [0u8; 32];
808 value0_array[16..].copy_from_slice(value0_slice);
809 value1_array[16..].copy_from_slice(value1_slice);
810 let value0 = Felt::from_bytes_be(&value0_array);
811 let value1 = Felt::from_bytes_be(&value1_array);
812 Ok(vec![value0, value1])
813 })
814 .unwrap_or(Err(PrimitiveError::MissingFieldElement)),
815 Primitive::Bool(value) => value
816 .map(|v| Ok(vec![if v { Felt::ONE } else { Felt::ZERO }]))
817 .unwrap_or(Err(PrimitiveError::MissingFieldElement)),
818 Primitive::ContractAddress(value) => {
819 value.map(|v| Ok(vec![v])).unwrap_or(Err(PrimitiveError::MissingFieldElement))
820 }
821 Primitive::ClassHash(value) => {
822 value.map(|v| Ok(vec![v])).unwrap_or(Err(PrimitiveError::MissingFieldElement))
823 }
824 Primitive::Felt252(value) => {
825 value.map(|v| Ok(vec![v])).unwrap_or(Err(PrimitiveError::MissingFieldElement))
826 }
827 Primitive::EthAddress(value) => {
828 value.map(|v| Ok(vec![v])).unwrap_or(Err(PrimitiveError::MissingFieldElement))
829 }
830 }
831 }
832}
833
834#[cfg(test)]
835mod tests {
836 use std::str::FromStr;
837
838 use crypto_bigint::U256;
839 use serde_json::json;
840 use starknet::core::types::Felt;
841
842 use super::Primitive;
843
844 #[test]
845 fn test_u256() {
846 let primitive = Primitive::U256(Some(U256::from_be_hex(
847 "aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbccccccccccccccccdddddddddddddddd",
848 )));
849 let sql_value = primitive.to_sql_value();
850 let serialized = primitive.serialize().unwrap();
851
852 let mut deserialized = primitive;
853 deserialized.deserialize(&mut serialized.clone()).unwrap();
854
855 assert_eq!(sql_value, "0xaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbccccccccccccccccdddddddddddddddd");
856 assert_eq!(
857 serialized,
858 vec![
859 Felt::from_str("0xccccccccccccccccdddddddddddddddd").unwrap(),
860 Felt::from_str("0xaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb").unwrap()
861 ]
862 );
863 assert_eq!(deserialized, primitive)
864 }
865
866 #[test]
867 fn inner_value_getter_setter() {
868 let mut primitive = Primitive::I8(None);
869 primitive.set_i8(Some(-1i8)).unwrap();
870 assert_eq!(primitive.as_i8(), Some(-1i8));
871 let mut primitive = Primitive::I16(None);
872 primitive.set_i16(Some(-1i16)).unwrap();
873 assert_eq!(primitive.as_i16(), Some(-1i16));
874 let mut primitive = Primitive::I32(None);
875 primitive.set_i32(Some(-1i32)).unwrap();
876 assert_eq!(primitive.as_i32(), Some(-1i32));
877 let mut primitive = Primitive::I64(None);
878 primitive.set_i64(Some(-1i64)).unwrap();
879 assert_eq!(primitive.as_i64(), Some(-1i64));
880 let mut primitive = Primitive::I128(None);
881 primitive.set_i128(Some(-1i128)).unwrap();
882 assert_eq!(primitive.as_i128(), Some(-1i128));
883 let mut primitive = Primitive::U8(None);
884 primitive.set_u8(Some(1u8)).unwrap();
885 assert_eq!(primitive.as_u8(), Some(1u8));
886 let mut primitive = Primitive::U16(None);
887 primitive.set_u16(Some(1u16)).unwrap();
888 assert_eq!(primitive.as_u16(), Some(1u16));
889 let mut primitive = Primitive::U32(None);
890 primitive.set_u32(Some(1u32)).unwrap();
891 assert_eq!(primitive.as_u32(), Some(1u32));
892 let mut primitive = Primitive::U64(None);
893 primitive.set_u64(Some(1u64)).unwrap();
894 assert_eq!(primitive.as_u64(), Some(1u64));
895 let mut primitive = Primitive::U128(None);
896 primitive.set_u128(Some(1u128)).unwrap();
897 assert_eq!(primitive.as_u128(), Some(1u128));
898 let mut primitive = Primitive::U256(None);
899 primitive.set_u256(Some(U256::from(1u128))).unwrap();
900 assert_eq!(primitive.as_u256(), Some(U256::from(1u128)));
901 let mut primitive = Primitive::Bool(None);
902 primitive.set_bool(Some(true)).unwrap();
903 assert!(primitive.as_bool().unwrap());
904 let mut primitive = Primitive::Felt252(None);
905 primitive.set_felt252(Some(Felt::from(1u128))).unwrap();
906 assert_eq!(primitive.as_felt252(), Some(Felt::from(1u128)));
907 let mut primitive = Primitive::ClassHash(None);
908 primitive.set_class_hash(Some(Felt::from(1u128))).unwrap();
909 assert_eq!(primitive.as_class_hash(), Some(Felt::from(1u128)));
910 let mut primitive = Primitive::ContractAddress(None);
911 primitive.set_contract_address(Some(Felt::from(1u128))).unwrap();
912 assert_eq!(primitive.as_contract_address(), Some(Felt::from(1u128)));
913 let mut primitive = Primitive::EthAddress(None);
914 primitive.set_eth_address(Some(Felt::from(1u128))).unwrap();
915 assert_eq!(primitive.as_eth_address(), Some(Felt::from(1u128)));
916 }
917
918 #[test]
919 fn test_primitive_deserialization() {
920 let test_cases = vec![
921 (vec![Felt::from(-42i8)], Primitive::I8(Some(-42))),
922 (vec![Felt::from(-1000i16)], Primitive::I16(Some(-1000))),
923 (vec![Felt::from(-100000i32)], Primitive::I32(Some(-100000))),
924 (vec![Felt::from(-1000000000i64)], Primitive::I64(Some(-1000000000))),
925 (
926 vec![Felt::from(-1000000000000000000i128)],
927 Primitive::I128(Some(-1000000000000000000)),
928 ),
929 (vec![Felt::from(42u8)], Primitive::U8(Some(42))),
930 (vec![Felt::from(1000u16)], Primitive::U16(Some(1000))),
931 (vec![Felt::from(100000u32)], Primitive::U32(Some(100000))),
932 (vec![Felt::from(1000000000u64)], Primitive::U64(Some(1000000000))),
933 (vec![Felt::from(1000000000000000000u128)], Primitive::U128(Some(1000000000000000000))),
934 (vec![Felt::from(1u8)], Primitive::Bool(Some(true))),
935 (vec![Felt::from(123456789u128)], Primitive::Felt252(Some(Felt::from(123456789)))),
936 (vec![Felt::from(987654321u128)], Primitive::ClassHash(Some(Felt::from(987654321)))),
937 (
938 vec![Felt::from(123456789u128)],
939 Primitive::ContractAddress(Some(Felt::from(123456789))),
940 ),
941 (vec![Felt::from(123456789u128)], Primitive::EthAddress(Some(Felt::from(123456789)))),
942 ];
943
944 for (serialized, expected) in test_cases {
945 let mut to_deser = expected;
946 to_deser.deserialize(&mut serialized.clone()).unwrap();
947 assert_eq!(to_deser, expected);
948 }
949 }
950
951 #[test]
952 fn test_sql_value_round_trip() {
953 let test_cases = vec![
954 Primitive::I8(Some(-42)),
955 Primitive::I16(Some(-1000)),
956 Primitive::I32(Some(-100000)),
957 Primitive::I64(Some(-1000000000)),
958 Primitive::I128(Some(-1000000000000000000)),
959 Primitive::U8(Some(42)),
960 Primitive::U16(Some(1000)),
961 Primitive::U32(Some(100000)),
962 Primitive::U64(Some(1000000000)),
963 Primitive::U128(Some(1000000000000000000)),
964 Primitive::U256(Some(U256::from_be_hex(
965 "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
966 ))),
967 Primitive::Bool(Some(true)),
968 Primitive::Bool(Some(false)),
969 Primitive::Felt252(Some(Felt::from(123456789))),
970 Primitive::ClassHash(Some(Felt::from(987654321))),
971 Primitive::ContractAddress(Some(Felt::from(123456789))),
972 Primitive::EthAddress(Some(Felt::from(123456789))),
973 ];
974
975 for original in test_cases {
976 let sql_value = original.to_sql_value();
978
979 let mut parsed = match original {
981 Primitive::I8(_) => Primitive::I8(None),
982 Primitive::I16(_) => Primitive::I16(None),
983 Primitive::I32(_) => Primitive::I32(None),
984 Primitive::I64(_) => Primitive::I64(None),
985 Primitive::I128(_) => Primitive::I128(None),
986 Primitive::U8(_) => Primitive::U8(None),
987 Primitive::U16(_) => Primitive::U16(None),
988 Primitive::U32(_) => Primitive::U32(None),
989 Primitive::U64(_) => Primitive::U64(None),
990 Primitive::U128(_) => Primitive::U128(None),
991 Primitive::U256(_) => Primitive::U256(None),
992 Primitive::Bool(_) => Primitive::Bool(None),
993 Primitive::Felt252(_) => Primitive::Felt252(None),
994 Primitive::ClassHash(_) => Primitive::ClassHash(None),
995 Primitive::ContractAddress(_) => Primitive::ContractAddress(None),
996 Primitive::EthAddress(_) => Primitive::EthAddress(None),
997 };
998
999 parsed.from_sql_value(&sql_value).unwrap();
1001
1002 assert_eq!(parsed, original, "Round trip failed for primitive: {:?}", original);
1004 }
1005 }
1006
1007 #[test]
1008 fn test_json_value_round_trip() {
1009 let test_cases = vec![
1010 Primitive::I8(Some(-42)),
1011 Primitive::I16(Some(-1000)),
1012 Primitive::I32(Some(-100000)),
1013 Primitive::I64(Some(-1000000000)),
1014 Primitive::I128(Some(-1000000000000000000)),
1015 Primitive::U8(Some(42)),
1016 Primitive::U16(Some(1000)),
1017 Primitive::U32(Some(100000)),
1018 Primitive::U64(Some(1000000000)),
1019 Primitive::U128(Some(1000000000000000000)),
1020 Primitive::U256(Some(U256::from_be_hex(
1021 "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
1022 ))),
1023 Primitive::Bool(Some(true)),
1024 Primitive::Bool(Some(false)),
1025 Primitive::Felt252(Some(Felt::from(123456789))),
1026 Primitive::ClassHash(Some(Felt::from(987654321))),
1027 Primitive::ContractAddress(Some(Felt::from(123456789))),
1028 Primitive::EthAddress(Some(Felt::from(123456789))),
1029 ];
1030
1031 for original in test_cases {
1032 let json_value = original.to_json_value().unwrap();
1034
1035 let mut parsed = match original {
1037 Primitive::I8(_) => Primitive::I8(None),
1038 Primitive::I16(_) => Primitive::I16(None),
1039 Primitive::I32(_) => Primitive::I32(None),
1040 Primitive::I64(_) => Primitive::I64(None),
1041 Primitive::I128(_) => Primitive::I128(None),
1042 Primitive::U8(_) => Primitive::U8(None),
1043 Primitive::U16(_) => Primitive::U16(None),
1044 Primitive::U32(_) => Primitive::U32(None),
1045 Primitive::U64(_) => Primitive::U64(None),
1046 Primitive::U128(_) => Primitive::U128(None),
1047 Primitive::U256(_) => Primitive::U256(None),
1048 Primitive::Bool(_) => Primitive::Bool(None),
1049 Primitive::Felt252(_) => Primitive::Felt252(None),
1050 Primitive::ClassHash(_) => Primitive::ClassHash(None),
1051 Primitive::ContractAddress(_) => Primitive::ContractAddress(None),
1052 Primitive::EthAddress(_) => Primitive::EthAddress(None),
1053 };
1054
1055 parsed.from_json_value(json_value).unwrap();
1057
1058 assert_eq!(parsed, original, "JSON round trip failed for primitive: {:?}", original);
1060 }
1061 }
1062
1063 #[test]
1064 fn test_json_value_types() {
1065 let small_int = Primitive::I32(Some(42));
1067 let json_val = small_int.to_json_value().unwrap();
1068 assert!(json_val.is_number());
1069 assert_eq!(json_val.as_i64().unwrap(), 42);
1070
1071 let large_int = Primitive::U128(Some(u128::MAX));
1073 let json_val = large_int.to_json_value().unwrap();
1074 assert!(json_val.is_string());
1075 assert_eq!(json_val.as_str().unwrap(), u128::MAX.to_string());
1076
1077 let u256_val = Primitive::U256(Some(U256::from(12345u128)));
1079 let json_val = u256_val.to_json_value().unwrap();
1080 assert!(json_val.is_string());
1081 let expected = format!("0x{:064x}", U256::from(12345u128));
1082 assert_eq!(json_val.as_str().unwrap(), expected);
1083
1084 let bool_val = Primitive::Bool(Some(true));
1086 let json_val = bool_val.to_json_value().unwrap();
1087 assert!(json_val.is_boolean());
1088 assert!(json_val.as_bool().unwrap());
1089
1090 let addr = Primitive::ContractAddress(Some(Felt::from(0x123456789abcdefu64)));
1092 let json_val = addr.to_json_value().unwrap();
1093 assert!(json_val.is_string());
1094 let expected = format!("0x{:064x}", Felt::from(0x123456789abcdefu64));
1095 assert_eq!(json_val.as_str().unwrap(), expected);
1096 }
1097
1098 #[test]
1099 fn test_json_parsing_edge_cases() {
1100 let mut bool_prim = Primitive::Bool(None);
1102 bool_prim.from_json_value(json!(1)).unwrap();
1103 assert!(bool_prim.as_bool().unwrap());
1104
1105 bool_prim.from_json_value(json!(0)).unwrap();
1106 assert!(!bool_prim.as_bool().unwrap());
1107
1108 let mut u128_prim = Primitive::U128(None);
1110 u128_prim.from_json_value(json!("255")).unwrap();
1111 assert_eq!(u128_prim.as_u128(), Some(255));
1112
1113 u128_prim.from_json_value(json!("0xff")).unwrap();
1115 assert_eq!(u128_prim.as_u128(), Some(255));
1116
1117 let mut u64_prim = Primitive::U64(None);
1118 u64_prim.from_json_value(json!("0x1234567890abcdef")).unwrap();
1119 assert_eq!(u64_prim.as_u64(), Some(0x1234567890abcdef));
1120
1121 u64_prim.from_json_value(json!("1311768467294899695")).unwrap(); assert_eq!(u64_prim.as_u64(), Some(0x1234567890abcdef));
1123
1124 let mut i128_prim = Primitive::I128(None);
1126 i128_prim.from_json_value(json!("-170141183460469231731687303715884105728")).unwrap();
1127 assert_eq!(i128_prim.as_i128(), Some(i128::MIN));
1128
1129 i128_prim.from_json_value(json!("0x80000000000000000000000000000000")).unwrap();
1131 assert_eq!(i128_prim.as_i128(), Some(i128::MIN));
1132
1133 let mut u256_prim = Primitive::U256(None);
1135 u256_prim.from_json_value(json!("0x1234567890abcdef")).unwrap();
1136 assert_eq!(
1137 u256_prim.as_u256(),
1138 Some(U256::from_be_hex(
1139 "0000000000000000000000000000000000000000000000001234567890abcdef"
1140 ))
1141 );
1142
1143 u256_prim.from_json_value(json!("1234567890abcdef")).unwrap();
1144 assert_eq!(
1145 u256_prim.as_u256(),
1146 Some(U256::from_be_hex(
1147 "0000000000000000000000000000000000000000000000001234567890abcdef"
1148 ))
1149 );
1150
1151 let mut i8_prim = Primitive::I8(None);
1153 assert!(i8_prim.from_json_value(json!(127)).is_ok()); assert!(i8_prim.from_json_value(json!(200)).is_err()); let mut u8_prim = Primitive::U8(None);
1157 assert!(u8_prim.from_json_value(json!(255)).is_ok()); assert!(u8_prim.from_json_value(json!(256)).is_err()); }
1160
1161 #[test]
1162 fn test_json_error_handling() {
1163 let mut i32_prim = Primitive::I32(None);
1165 assert!(i32_prim.from_json_value(json!("not_a_number")).is_err());
1166 assert!(i32_prim.from_json_value(json!(true)).is_err());
1167
1168 let none_prim = Primitive::I32(None);
1170 assert!(none_prim.to_json_value().is_err());
1171
1172 let mut felt_prim = Primitive::Felt252(None);
1174 assert!(felt_prim.from_json_value(json!("0xgg")).is_err());
1175 }
1176}