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