1use crate::layered::{Anulap, Initialize};
4
5#[cfg(any(feature = "with-source-clap", feature = "with-source-on"))]
6use crate::layered::Source;
7
8#[cfg(feature = "with-source-clap")]
10#[derive(Debug)]
11pub struct ClapSource<'a> {
12 matches: clap::ArgMatches<'a>,
13}
14
15#[cfg(feature = "with-source-clap")]
16impl<'a> ClapSource<'a> {
17 pub fn new(matches: clap::ArgMatches<'a>) -> Self {
19 Self { matches }
20 }
21}
22
23#[cfg(feature = "with-source-clap")]
24impl<'a> Source for ClapSource<'a> {
25 fn get(&self, key: &str) -> Option<String> {
26 self.matches.value_of(key).map(String::from)
27 }
28}
29
30#[cfg(feature = "with-source-ron")]
32#[derive(Debug)]
33pub struct RonSource {
34 value: ron::Value,
35}
36
37#[cfg(feature = "with-source-ron")]
38impl RonSource {
39 pub fn from_file<P>(path: P) -> Result<Self, RonSourceError>
41 where
42 P: AsRef<std::path::Path>,
43 {
44 let file = std::fs::OpenOptions::new().read(true).open(path)?;
45 let mut reader = std::io::BufReader::new(file);
46
47 let value = ron::de::from_reader(&mut reader)?;
48
49 Ok(Self { value })
50 }
51}
52
53#[cfg(feature = "with-source-ron")]
54impl Source for RonSource {
55 fn get(&self, key: &str) -> Option<String> {
56 match &self.value {
57 ron::Value::Map(map) => map
58 .iter()
59 .find(|(k, _)| match k {
60 ron::Value::String(k) => k == key,
61 _ => false,
62 })
63 .and_then(|(_, value)| -> Option<String> {
64 match value {
65 ron::Value::Bool(boolean) => Some(boolean.to_string()),
66 ron::Value::Number(number) => match number {
67 ron::Number::Integer(integer) => Some(integer.to_string()),
68 ron::Number::Float(float) => Some(float.get().to_string()),
69 },
70 ron::Value::String(string) => Some(string.clone()),
71 _ => None,
72 }
73 }),
74 _ => None,
75 }
76 }
77}
78
79#[cfg(feature = "with-source-ron")]
81#[derive(Debug)]
82pub enum RonSourceError {
83 IO { source: std::io::Error },
84 Ron { source: ron::Error },
85}
86
87#[cfg(feature = "with-source-ron")]
88impl std::fmt::Display for RonSourceError {
89 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90 match self {
91 RonSourceError::IO { source } => write!(f, "ron source, io error: {}", source),
92 RonSourceError::Ron { source } => {
93 write!(f, "ron source, ron deserialize error: {}", source)
94 }
95 }
96 }
97}
98
99#[cfg(feature = "with-source-ron")]
100impl std::error::Error for RonSourceError {
101 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
102 match self {
103 RonSourceError::IO { source } => Some(source),
104 RonSourceError::Ron { source } => Some(source),
105 }
106 }
107}
108
109#[cfg(feature = "with-source-ron")]
110impl From<std::io::Error> for RonSourceError {
111 fn from(source: std::io::Error) -> Self {
112 Self::IO { source }
113 }
114}
115
116#[cfg(feature = "with-source-ron")]
117impl From<ron::Error> for RonSourceError {
118 fn from(source: ron::Error) -> Self {
119 Self::Ron { source }
120 }
121}
122
123#[derive(Clone, Debug, serde::Deserialize)]
125#[serde(default)]
126pub struct Config {
127 pub ip: [u8; 4],
133
134 pub port: u16,
140
141 pub database: String,
172}
173
174impl Initialize for Config {
175 fn init(config: &Anulap<'_>) -> Option<Self> {
176 Some(Self {
177 ip: config
178 .get("ip")
179 .and_then(|value| {
180 let mut parts = value
181 .split('.')
182 .map(str::parse)
183 .collect::<Vec<Result<u8, _>>>();
184
185 let four = parts.pop()?.ok()?;
186 let three = parts.pop()?.ok()?;
187 let two = parts.pop()?.ok()?;
188 let one = parts.pop()?.ok()?;
189
190 Some([one, two, three, four])
191 })
192 .unwrap_or_else(|| [0, 0, 0, 0]),
193 port: config
194 .get("port")
195 .and_then(|value| value.parse().ok())
196 .unwrap_or(8901),
197 database: config
198 .get("database")
199 .unwrap_or_else(|| String::from("postgres://stry:stry@localhost:5432/stry")),
200 })
201 }
202}
203
204impl Default for Config {
205 fn default() -> Self {
206 Self {
207 ip: [0, 0, 0, 0],
208 port: 8901,
209 database: String::from("postgres://stry:stry@localhost:5432/stry"),
210 }
211 }
212}