dojo_types/
primitive.rs

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        /// The actual selector value that was invalid.
59        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
95/// Macro to generate setter methods for Primitive enum variants.
96macro_rules! set_primitive {
97    ($method_name:ident, $variant:ident, $type:ty) => {
98        /// Sets the inner value of the `Primitive` enum if variant matches.
99        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
111/// Macro to generate getter methods for Primitive enum variants.
112macro_rules! as_primitive {
113    ($method_name:ident, $variant:ident, $type:ty) => {
114        /// If the `Primitive` is variant type, returns the associated vartiant value. Returns
115        /// `None` otherwise.
116        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            // sqlite integer is 64-bit signed integer
188            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            // u64 cannot fit into a i64, so we use text
198            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            // SQLite integers (signed 64-bit)
212            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            // Large integers and addresses as hex strings (for SQLite TEXT)
222            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            // SQLite integers - parse directly
236            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            // I128 stored as hex string - need to handle two's complement properly
293            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                // Parse as u128 first, then convert to i128 via two's complement
299                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            // Large integers stored as hex strings in SQLite TEXT
305            Primitive::U64(ref mut inner) => {
306                // Handle both hex (expected from SQL) and decimal (fallback)
307                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                    // Fallback to decimal parsing
314                    *inner = Some(
315                        value
316                            .parse()
317                            .map_err(|_| PrimitiveError::InvalidSqlValue(value.to_string()))?,
318                    );
319                }
320            }
321            Primitive::U128(ref mut inner) => {
322                // Handle both hex (expected from SQL) and decimal (fallback)
323                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                    // Fallback to decimal parsing
330                    *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                // Pad hex string to 64 characters if needed
342                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    /// Convert to JSON Value with proper type representation
386    pub fn to_json_value(&self) -> Result<JsonValue, PrimitiveError> {
387        match self {
388            // Small integers that fit in JSON Number safely (up to 2^53 - 1)
389            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            // Large integers as decimal strings for JSON
398            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            // U256 as hex string due to its extremely large range
404            Primitive::U256(Some(v)) => Ok(json!(format!("0x{:064x}", v))),
405
406            // Blockchain-specific types as hex strings
407            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            // None values
413            _ => Err(PrimitiveError::MissingFieldElement),
414        }
415    }
416
417    /// Parse from JSON Value with proper type validation
418    pub fn from_json_value(&mut self, value: JsonValue) -> Result<(), PrimitiveError> {
419        match (self, value) {
420            // Boolean handling
421            (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            // Small signed integers from JSON numbers
436            (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            // Small unsigned integers from JSON numbers
489            (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            // Large integers from strings (decimal) or numbers
542            (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            // String parsing for large integers and addresses
561            (primitive, JsonValue::String(s)) => {
562                match primitive {
563                    Primitive::I128(ref mut inner) => {
564                        // Handle both decimal and hex strings
565                        if let Some(hex_str) = s.strip_prefix("0x") {
566                            // Parse as u128 first, then convert to i128 via two's complement (same
567                            // as SQL parsing)
568                            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                        // Handle both decimal and hex strings
580                        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                        // Handle both decimal and hex strings
592                        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                        // U256 should always be hex strings
604                        let hex_str = s.strip_prefix("0x").unwrap_or(&s);
605                        // Pad hex string to 64 characters if needed
606                        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            // Convert to SQL value
977            let sql_value = original.to_sql_value();
978
979            // Create empty primitive of same type
980            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            // Parse back from SQL value
1000            parsed.from_sql_value(&sql_value).unwrap();
1001
1002            // Should match original
1003            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            // Convert to JSON value
1033            let json_value = original.to_json_value().unwrap();
1034
1035            // Create empty primitive of same type
1036            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            // Parse back from JSON value
1056            parsed.from_json_value(json_value).unwrap();
1057
1058            // Should match original
1059            assert_eq!(parsed, original, "JSON round trip failed for primitive: {:?}", original);
1060        }
1061    }
1062
1063    #[test]
1064    fn test_json_value_types() {
1065        // Test that small integers are represented as JSON numbers
1066        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        // Test that large integers are represented as decimal strings
1072        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        // Test that U256 is always represented as hex string
1078        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        // Test boolean representation
1085        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        // Test contract address representation
1091        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        // Test parsing boolean from number
1101        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        // Test parsing decimal strings for large integers
1109        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        // Test parsing hex strings for large integers
1114        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(); // Same value in decimal
1122        assert_eq!(u64_prim.as_u64(), Some(0x1234567890abcdef));
1123
1124        // Test parsing large decimal numbers
1125        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        // Test parsing hex for I128 (should handle two's complement)
1130        i128_prim.from_json_value(json!("0x80000000000000000000000000000000")).unwrap();
1131        assert_eq!(i128_prim.as_i128(), Some(i128::MIN));
1132
1133        // Test U256 parsing from hex strings (with and without 0x prefix)
1134        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        // Test range validation for small integers
1152        let mut i8_prim = Primitive::I8(None);
1153        assert!(i8_prim.from_json_value(json!(127)).is_ok()); // Valid i8
1154        assert!(i8_prim.from_json_value(json!(200)).is_err()); // Out of range for i8
1155
1156        let mut u8_prim = Primitive::U8(None);
1157        assert!(u8_prim.from_json_value(json!(255)).is_ok()); // Valid u8
1158        assert!(u8_prim.from_json_value(json!(256)).is_err()); // Out of range for u8
1159    }
1160
1161    #[test]
1162    fn test_json_error_handling() {
1163        // Test type mismatch errors
1164        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        // Test missing field element error
1169        let none_prim = Primitive::I32(None);
1170        assert!(none_prim.to_json_value().is_err());
1171
1172        // Test invalid hex string
1173        let mut felt_prim = Primitive::Felt252(None);
1174        assert!(felt_prim.from_json_value(json!("0xgg")).is_err());
1175    }
1176}