1use ethereum_types::U64;
20use serde::{de, Deserialize, Serialize};
21
22#[derive(Copy, Clone, Debug, Eq, PartialEq)]
24pub enum SyncingStatus {
25 IsSyncing(SyncingProgress),
27 NotSyncing,
29}
30
31impl serde::Serialize for SyncingStatus {
32 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
33 where
34 S: serde::Serializer,
35 {
36 match self {
37 Self::IsSyncing(progress) => progress.serialize(serializer),
38 Self::NotSyncing => serializer.serialize_bool(false),
39 }
40 }
41}
42
43impl<'de> serde::Deserialize<'de> for SyncingStatus {
44 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
45 where
46 D: serde::Deserializer<'de>,
47 {
48 #[derive(Deserialize)]
49 #[serde(untagged)]
50 enum Syncing {
51 IsSyncing(SyncingProgress),
52 NotSyncing(bool),
53 }
54
55 match Syncing::deserialize(deserializer)? {
56 Syncing::IsSyncing(sync) => Ok(Self::IsSyncing(sync)),
57 Syncing::NotSyncing(false) => Ok(Self::NotSyncing),
58 Syncing::NotSyncing(true) => Err(de::Error::custom(
59 "eth_syncing should always return false if not syncing.",
60 )),
61 }
62 }
63}
64
65#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
67#[serde(rename_all = "camelCase")]
68pub struct SyncingProgress {
69 pub starting_block: U64,
71 pub current_block: U64,
73 pub highest_block: U64,
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
82 fn syncing_status_serde_impl() {
83 let valid_cases = [
84 (
85 r#"{"startingBlock":"0x64","currentBlock":"0xc8","highestBlock":"0x12c"}"#,
86 SyncingStatus::IsSyncing(SyncingProgress {
87 starting_block: 100.into(),
88 current_block: 200.into(),
89 highest_block: 300.into(),
90 }),
91 ),
92 ("false", SyncingStatus::NotSyncing),
93 ];
94 for (raw, typed) in valid_cases {
95 let deserialized = serde_json::from_str::<SyncingStatus>(raw).unwrap();
96 assert_eq!(deserialized, typed);
97
98 let serialized = serde_json::to_string(&typed).unwrap();
99 assert_eq!(serialized, raw);
100 }
101
102 let invalid_cases = ["true"];
103 for raw in invalid_cases {
104 let status: Result<SyncingStatus, _> = serde_json::from_str(raw);
105 assert!(status.is_err());
106 }
107 }
108}