fc_rpc_v2_types/
index.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// This file is part of Frontier.

// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use std::fmt;

#[derive(Copy, Clone, PartialEq, Eq, Default, Hash)]
pub struct Index(usize);

impl fmt::Debug for Index {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
		fmt::LowerHex::fmt(&self.0, f)
	}
}

impl fmt::Display for Index {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
		fmt::LowerHex::fmt(&self.0, f)
	}
}

impl From<Index> for usize {
	fn from(idx: Index) -> Self {
		idx.0
	}
}

impl From<usize> for Index {
	fn from(value: usize) -> Self {
		Self(value)
	}
}

impl serde::Serialize for Index {
	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
	where
		S: serde::Serializer,
	{
		serializer.serialize_str(&format!("0x{:x}", self.0))
	}
}

impl<'de> serde::Deserialize<'de> for Index {
	fn deserialize<D>(deserializer: D) -> Result<Index, D::Error>
	where
		D: serde::Deserializer<'de>,
	{
		use serde::de;

		struct IndexVisitor;

		impl de::Visitor<'_> for IndexVisitor {
			type Value = Index;

			fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
				formatter.write_str("hex-encoded or decimal index")
			}

			fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
			where
				E: de::Error,
			{
				Ok(Index(value as usize))
			}

			fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
			where
				E: de::Error,
			{
				if let Some(val) = value.strip_prefix("0x") {
					usize::from_str_radix(val, 16)
						.map(Index)
						.map_err(de::Error::custom)
				} else {
					value.parse::<usize>().map(Index).map_err(de::Error::custom)
				}
			}

			fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
			where
				E: de::Error,
			{
				self.visit_str(value.as_ref())
			}
		}

		deserializer.deserialize_any(IndexVisitor)
	}
}

#[cfg(test)]
mod tests {
	use super::*;

	#[test]
	fn index_serialize() {
		let indexes = vec![Index(10), Index(10), Index(u32::MAX as usize)];
		let serialized = serde_json::to_string(&indexes).unwrap();
		let expected = r#"["0xa","0xa","0xffffffff"]"#;
		assert_eq!(serialized, expected);
	}

	#[test]
	fn index_deserialize() {
		let s = r#"["0xa", "10", "0xffffffff"]"#;
		let deserialized: Vec<Index> = serde_json::from_str(s).unwrap();
		let expected = vec![Index(10), Index(10), Index(u32::MAX as usize)];
		assert_eq!(deserialized, expected);
	}
}