1use core::fmt;
4use core::str::FromStr;
5
6use bitcoin::Network as BtcNetwork;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)]
10pub enum Network {
11 #[default]
13 Mainnet,
14 Testnet,
16}
17
18impl Network {
19 #[inline]
21 #[must_use]
22 pub const fn to_bitcoin_network(self) -> BtcNetwork {
23 match self {
24 Self::Mainnet => BtcNetwork::Bitcoin,
25 Self::Testnet => BtcNetwork::Testnet,
26 }
27 }
28
29 #[inline]
31 #[must_use]
32 pub const fn coin_type(self) -> u32 {
33 match self {
34 Self::Mainnet => 0,
35 Self::Testnet => 1,
36 }
37 }
38
39 #[inline]
41 #[must_use]
42 pub const fn name(self) -> &'static str {
43 match self {
44 Self::Mainnet => "mainnet",
45 Self::Testnet => "testnet",
46 }
47 }
48}
49
50impl fmt::Display for Network {
51 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52 write!(f, "{}", self.name())
53 }
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
58pub struct ParseNetworkError;
59
60impl fmt::Display for ParseNetworkError {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 write!(f, "invalid network, expected: mainnet or testnet")
63 }
64}
65
66#[cfg(feature = "std")]
67impl std::error::Error for ParseNetworkError {}
68
69impl FromStr for Network {
70 type Err = ParseNetworkError;
71
72 fn from_str(s: &str) -> Result<Self, Self::Err> {
73 match s.to_lowercase().as_str() {
74 "mainnet" | "main" | "bitcoin" => Ok(Self::Mainnet),
75 "testnet" | "test" | "testnet3" | "testnet4" => Ok(Self::Testnet),
76 _ => Err(ParseNetworkError),
77 }
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn test_network_from_str() {
87 assert_eq!("mainnet".parse::<Network>().unwrap(), Network::Mainnet);
88 assert_eq!("main".parse::<Network>().unwrap(), Network::Mainnet);
89 assert_eq!("bitcoin".parse::<Network>().unwrap(), Network::Mainnet);
90 assert_eq!("testnet".parse::<Network>().unwrap(), Network::Testnet);
91 assert_eq!("test".parse::<Network>().unwrap(), Network::Testnet);
92 }
93
94 #[test]
95 fn test_network_from_str_case_insensitive() {
96 assert_eq!("MAINNET".parse::<Network>().unwrap(), Network::Mainnet);
97 assert_eq!("TESTNET".parse::<Network>().unwrap(), Network::Testnet);
98 }
99
100 #[test]
101 fn test_network_from_str_invalid() {
102 assert!("invalid".parse::<Network>().is_err());
103 assert!("".parse::<Network>().is_err());
104 }
105
106 #[test]
107 fn test_network_coin_type() {
108 assert_eq!(Network::Mainnet.coin_type(), 0);
109 assert_eq!(Network::Testnet.coin_type(), 1);
110 }
111
112 #[test]
113 fn test_network_default() {
114 assert_eq!(Network::default(), Network::Mainnet);
115 }
116
117 #[test]
118 fn test_network_display() {
119 assert_eq!(Network::Mainnet.to_string(), "mainnet");
120 assert_eq!(Network::Testnet.to_string(), "testnet");
121 }
122}