1#![no_std]
10#![warn(missing_docs)]
12#![warn(deprecated_in_future)]
13#![doc(test(attr(warn(unused))))]
14
15#[cfg(feature = "std")]
16extern crate std;
17
18#[cfg(feature = "serde")]
19pub extern crate serde;
20
21use core::fmt;
22use core::str::FromStr;
23
24#[cfg(feature = "arbitrary")]
25use arbitrary::{Arbitrary, Unstructured};
26use internals::error::InputString;
27#[cfg(feature = "serde")]
28use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
29
30#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
32#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
33pub enum NetworkKind {
34 Main,
36 Test,
38}
39
40impl NetworkKind {
41 pub const fn is_mainnet(self) -> bool {
43 matches!(self, Self::Main)
44 }
45}
46
47impl From<Network> for NetworkKind {
48 fn from(network: Network) -> Self {
49 match network {
50 Network::Tidecoin => Self::Main,
51 Network::Testnet | Network::Regtest => Self::Test,
52 }
53 }
54}
55
56#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Hash, Debug)]
65pub enum Network {
66 Tidecoin,
68 Testnet,
70 Regtest,
72}
73
74#[cfg(feature = "serde")]
75impl Serialize for Network {
76 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
77 where
78 S: Serializer,
79 {
80 serializer.serialize_str(self.as_display_str())
81 }
82}
83
84#[cfg(feature = "serde")]
85impl<'de> Deserialize<'de> for Network {
86 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
87 where
88 D: Deserializer<'de>,
89 {
90 struct NetworkVisitor;
91
92 impl Visitor<'_> for NetworkVisitor {
93 type Value = Network;
94
95 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
96 formatter.write_str("a valid network identifier")
97 }
98
99 fn visit_str<E>(self, value: &str) -> Result<Network, E>
100 where
101 E: serde::de::Error,
102 {
103 Network::from_str(value).map_err(E::custom)
104 }
105 }
106
107 deserializer.deserialize_str(NetworkVisitor)
108 }
109}
110
111impl Network {
112 pub fn to_core_arg(self) -> &'static str {
116 match self {
117 Self::Tidecoin => "main",
118 Self::Testnet => "test",
119 Self::Regtest => "regtest",
120 }
121 }
122
123 pub fn from_core_arg(core_arg: &str) -> Result<Self, ParseNetworkError> {
132 let network = match core_arg {
133 "main" => Self::Tidecoin,
134 "test" => Self::Testnet,
135 "regtest" => Self::Regtest,
136 _ => return Err(ParseNetworkError(InputString::from(core_arg))),
137 };
138 Ok(network)
139 }
140
141 const fn as_display_str(self) -> &'static str {
143 match self {
144 Self::Tidecoin => "tidecoin",
145 Self::Testnet => "testnet",
146 Self::Regtest => "regtest",
147 }
148 }
149}
150
151impl fmt::Display for Network {
152 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
153 write!(f, "{}", self.as_display_str())
154 }
155}
156
157#[cfg(feature = "serde")]
158pub mod as_core_arg {
159 #![allow(missing_docs)]
163 #![allow(clippy::missing_errors_doc)]
164
165 use crate::Network;
166
167 #[allow(clippy::trivially_copy_pass_by_ref)] pub fn serialize<S>(network: &Network, serializer: S) -> Result<S::Ok, S::Error>
169 where
170 S: serde::Serializer,
171 {
172 serializer.serialize_str(network.to_core_arg())
173 }
174
175 pub fn deserialize<'de, D>(deserializer: D) -> Result<Network, D::Error>
176 where
177 D: serde::Deserializer<'de>,
178 {
179 struct NetworkVisitor;
180
181 impl serde::de::Visitor<'_> for NetworkVisitor {
182 type Value = Network;
183
184 fn visit_str<E: serde::de::Error>(self, s: &str) -> Result<Self::Value, E> {
185 Network::from_core_arg(s).map_err(|_| {
186 E::invalid_value(
187 serde::de::Unexpected::Str(s),
188 &"tidecoin network encoded as a string (either main, test, or regtest)",
189 )
190 })
191 }
192
193 fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
194 write!(
195 formatter,
196 "tidecoin network encoded as a string (either main, test, or regtest)"
197 )
198 }
199 }
200
201 deserializer.deserialize_str(NetworkVisitor)
202 }
203}
204
205#[derive(Debug, Clone, PartialEq, Eq)]
207#[non_exhaustive]
208pub struct ParseNetworkError(InputString);
209
210impl fmt::Display for ParseNetworkError {
211 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
212 write!(f, "{}", self.0.display_cannot_parse("network"))
214 }
215}
216
217#[cfg(feature = "std")]
218impl std::error::Error for ParseNetworkError {
219 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
220 None
221 }
222}
223
224impl FromStr for Network {
225 type Err = ParseNetworkError;
226
227 #[inline]
228 fn from_str(s: &str) -> Result<Self, Self::Err> {
229 match s {
230 "tidecoin" | "main" => Ok(Self::Tidecoin),
231 "testnet" | "test" => Ok(Self::Testnet),
232 "regtest" => Ok(Self::Regtest),
233 _ => Err(ParseNetworkError(InputString::from(s))),
234 }
235 }
236}
237
238impl AsRef<Self> for Network {
239 fn as_ref(&self) -> &Self {
240 self
241 }
242}
243
244#[cfg(feature = "arbitrary")]
245impl<'a> Arbitrary<'a> for NetworkKind {
246 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
247 match bool::arbitrary(u)? {
248 true => Ok(Self::Main),
249 false => Ok(Self::Test),
250 }
251 }
252}
253
254#[cfg(test)]
255mod tests {
256 #[cfg(feature = "std")]
257 use std::string::ToString;
258
259 #[cfg(feature = "serde")]
260 use serde::{Deserialize, Serialize};
261
262 use super::Network;
263
264 #[test]
265 #[cfg(feature = "std")]
266 fn string() {
267 assert_eq!(Network::Tidecoin.to_string(), "tidecoin");
268 assert_eq!(Network::Testnet.to_string(), "testnet");
269 assert_eq!(Network::Regtest.to_string(), "regtest");
270
271 assert_eq!("tidecoin".parse::<Network>().unwrap(), Network::Tidecoin);
272 assert_eq!("main".parse::<Network>().unwrap(), Network::Tidecoin);
273 assert_eq!("testnet".parse::<Network>().unwrap(), Network::Testnet);
274 assert_eq!("test".parse::<Network>().unwrap(), Network::Testnet);
275 assert_eq!("regtest".parse::<Network>().unwrap(), Network::Regtest);
276 assert!("fakenet".parse::<Network>().is_err());
277 }
278
279 #[test]
280 #[cfg(feature = "serde")]
281 #[cfg(feature = "std")]
282 fn serde_roundtrip() {
283 use std::{format, vec};
284
285 use Network::*;
286 let tests = vec![(Tidecoin, "tidecoin"), (Testnet, "testnet"), (Regtest, "regtest")];
287
288 for tc in tests {
289 let network = tc.0;
290
291 let want = format!("\"{}\"", tc.1);
292 let got = serde_json::to_string(&tc.0).expect("failed to serialize network");
293 assert_eq!(got, want);
294
295 let back: Network = serde_json::from_str(&got).expect("failed to deserialize network");
296 assert_eq!(back, network);
297 }
298 }
299
300 #[test]
301 fn from_to_core_arg() {
302 let expected_pairs = [
303 (Network::Tidecoin, "main"),
304 (Network::Testnet, "test"),
305 (Network::Regtest, "regtest"),
306 ];
307
308 for (net, core_arg) in &expected_pairs {
309 assert_eq!(Network::from_core_arg(core_arg), Ok(*net));
310 assert_eq!(net.to_core_arg(), *core_arg);
311 }
312 }
313
314 #[test]
315 #[cfg(feature = "serde")]
316 fn serde_as_core_arg() {
317 #[derive(Serialize, Deserialize, PartialEq, Debug)]
318 struct T {
319 #[serde(with = "crate::as_core_arg")]
320 pub network: Network,
321 }
322
323 serde_test::assert_tokens(
324 &T { network: Network::Tidecoin },
325 &[
326 serde_test::Token::Struct { name: "T", len: 1 },
327 serde_test::Token::Str("network"),
328 serde_test::Token::Str("main"),
329 serde_test::Token::StructEnd,
330 ],
331 );
332 }
333}