antelope/chain/
block_id.rs

1use crate::chain::{Decoder, Encoder, Packer};
2use antelope_client_macros::StructPacker;
3use serde::{
4    de::{self, Visitor},
5    Deserializer,
6};
7use serde::{Deserialize, Serialize};
8use std::fmt;
9use std::fmt::{Display, Formatter};
10
11#[derive(Clone, Default, Eq, PartialEq, StructPacker, Serialize, Deserialize, Debug)]
12pub struct BlockId {
13    pub bytes: Vec<u8>,
14}
15
16impl BlockId {
17    pub fn from_bytes(bytes: &[u8]) -> Result<Self, String> {
18        if bytes.len() != 32 {
19            return Err(String::from(
20                "BlockId.from_bytes expected bytes length of 32",
21            ));
22        }
23        Ok(Self {
24            bytes: bytes.to_vec(),
25        })
26    }
27
28    pub fn block_num(&self) -> u32 {
29        let num_bytes = &self.bytes[0..4];
30        (u32::from(num_bytes[0]) << 24)
31            | (u32::from(num_bytes[1]) << 16)
32            | (u32::from(num_bytes[2]) << 8)
33            | u32::from(num_bytes[3])
34    }
35
36    pub fn as_string(&self) -> String {
37        self.block_num().to_string()
38    }
39}
40
41impl Display for BlockId {
42    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
43        write!(f, "{}", self.as_string())
44    }
45}
46
47pub(crate) fn deserialize_block_id<'de, D>(deserializer: D) -> Result<BlockId, D::Error>
48where
49    D: Deserializer<'de>,
50{
51    struct BlockIdVisitor;
52
53    impl<'de> Visitor<'de> for BlockIdVisitor {
54        type Value = BlockId;
55
56        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
57            formatter.write_str("a hex string for BlockId")
58        }
59
60        fn visit_str<E>(self, value: &str) -> Result<BlockId, E>
61        where
62            E: de::Error,
63        {
64            if value.len() != 64 {
65                // 64 hex chars = 32 bytes
66                return Err(E::custom(
67                    "BlockId hex string must be exactly 64 characters long",
68                ));
69            }
70
71            let mut bytes = Vec::new();
72            for i in 0..32 {
73                // Process 32 bytes
74                let byte_slice = &value[i * 2..i * 2 + 2];
75                match u8::from_str_radix(byte_slice, 16) {
76                    Ok(byte) => bytes.push(byte),
77                    Err(_) => return Err(E::custom("Invalid hex string for BlockId")),
78                }
79            }
80
81            Ok(BlockId { bytes })
82        }
83    }
84
85    deserializer.deserialize_str(BlockIdVisitor)
86}
87
88pub(crate) fn deserialize_optional_block_id<'de, D>(
89    deserializer: D,
90) -> Result<Option<BlockId>, D::Error>
91where
92    D: Deserializer<'de>,
93{
94    // Deserialize the input as an Option<String>. If it's None, directly return Ok(None).
95    let opt: Option<String> = Option::deserialize(deserializer)?;
96    // Map the Option<String> to Option<BlockId> by converting the hex string to bytes and then using from_bytes.
97    let result = match opt {
98        Some(str_val) => {
99            let mut bytes = Vec::new();
100            for i in 0..(str_val.len() / 2) {
101                let byte_slice = &str_val[i * 2..i * 2 + 2];
102                match u8::from_str_radix(byte_slice, 16) {
103                    Ok(byte) => bytes.push(byte),
104                    Err(_) => {
105                        return Err(serde::de::Error::custom("Invalid hex string for BlockId"))
106                    }
107                }
108            }
109            // Here you use from_bytes, which you should already have implemented in your BlockId struct.
110            BlockId::from_bytes(&bytes)
111                .map(Some)
112                .map_err(serde::de::Error::custom)?
113        }
114        None => None,
115    };
116    Ok(result)
117}