1use nym_network_defaults::mainnet::read_var_if_not_default;
5use nym_network_defaults::var_names::CONFIGURED;
6use std::any::type_name;
7use std::fmt::Debug;
8use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
9use std::str::FromStr;
10
11pub const MISSING_VALUE: &str = "MISSING VALUE";
12
13pub fn missing_string_value<T: From<String>>() -> T {
15 MISSING_VALUE.to_string().into()
16}
17
18pub fn inaddr_any() -> IpAddr {
20 IpAddr::V4(Ipv4Addr::UNSPECIFIED)
21}
22
23pub fn in6addr_any_init() -> IpAddr {
25 IpAddr::V6(Ipv6Addr::UNSPECIFIED)
26}
27
28pub trait OptionalSet {
30 fn with_optional<F, T>(self, f: F, val: Option<T>) -> Self
33 where
34 F: Fn(Self, T) -> Self,
35 Self: Sized,
36 {
37 if let Some(val) = val {
38 f(self, val)
39 } else {
40 self
41 }
42 }
43
44 fn with_validated_optional<F, T, V, E>(
47 self,
48 f: F,
49 value: Option<T>,
50 validate: V,
51 ) -> Result<Self, E>
52 where
53 F: Fn(Self, T) -> Self,
54 V: Fn(&T) -> Result<(), E>,
55 Self: Sized,
56 {
57 if let Some(val) = value {
58 validate(&val)?;
59 Ok(f(self, val))
60 } else {
61 Ok(self)
62 }
63 }
64
65 fn with_optional_env<F, T>(self, f: F, val: Option<T>, env_var: &str) -> Self
70 where
71 F: Fn(Self, T) -> Self,
72 T: FromStr,
73 <T as FromStr>::Err: Debug,
74 Self: Sized,
75 {
76 if let Some(val) = val {
77 return f(self, val);
78 } else if std::env::var(CONFIGURED).is_ok() {
79 if let Some(raw) = read_var_if_not_default(env_var) {
80 return f(
81 self,
82 raw.parse().unwrap_or_else(|err| {
83 panic!(
84 "failed to parse value of {raw} into type {}. the error was {:?}",
85 type_name::<T>(),
86 err
87 )
88 }),
89 );
90 }
91 }
92 self
93 }
94
95 fn with_optional_custom_env<F, T, G>(
100 self,
101 f: F,
102 val: Option<T>,
103 env_var: &str,
104 parser: G,
105 ) -> Self
106 where
107 F: Fn(Self, T) -> Self,
108 G: Fn(&str) -> T,
109 Self: Sized,
110 {
111 if let Some(val) = val {
112 return f(self, val);
113 } else if std::env::var(CONFIGURED).is_ok() {
114 if let Some(raw) = read_var_if_not_default(env_var) {
115 return f(self, parser(&raw));
116 }
117 }
118 self
119 }
120}
121
122#[macro_export]
125macro_rules! define_optional_set_inner {
126 ( $x: ident, $inner_field_name: ident, $inner_field_typ: ty ) => {
127 impl $x {
128 pub fn with_optional_inner<F, T>(mut self, f: F, val: Option<T>) -> Self
129 where
130 F: Fn($inner_field_typ, T) -> $inner_field_typ,
131 {
132 self.$inner_field_name = self.$inner_field_name.with_optional(f, val);
133 self
134 }
135
136 pub fn with_validated_optional_inner<F, T, V, E>(
137 mut self,
138 f: F,
139 value: Option<T>,
140 validate: V,
141 ) -> Result<Self, E>
142 where
143 F: Fn($inner_field_typ, T) -> $inner_field_typ,
144 V: Fn(&T) -> Result<(), E>,
145 {
146 self.$inner_field_name = self
147 .$inner_field_name
148 .with_validated_optional(f, value, validate)?;
149 Ok(self)
150 }
151
152 pub fn with_optional_env_inner<F, T>(
153 mut self,
154 f: F,
155 val: Option<T>,
156 env_var: &str,
157 ) -> Self
158 where
159 F: Fn($inner_field_typ, T) -> $inner_field_typ,
160 T: FromStr,
161 <T as FromStr>::Err: Debug,
162 {
163 self.$inner_field_name = self.$inner_field_name.with_optional_env(f, val, env_var);
164 self
165 }
166
167 pub fn with_optional_custom_env_inner<F, T, G>(
168 mut self,
169 f: F,
170 val: Option<T>,
171 env_var: &str,
172 parser: G,
173 ) -> Self
174 where
175 F: Fn($inner_field_typ, T) -> $inner_field_typ,
176 G: Fn(&str) -> T,
177 {
178 self.$inner_field_name = self
179 .$inner_field_name
180 .with_optional_custom_env(f, val, env_var, parser);
181 self
182 }
183 }
184 };
185}
186
187pub fn parse_urls(raw: &str) -> Vec<url::Url> {
189 raw.split(',')
190 .map(|raw_url| {
191 raw_url
192 .trim()
193 .parse()
194 .expect("one of the provided urls was invalid")
195 })
196 .collect()
197}
198
199impl<T> OptionalSet for T {}