yellowstone_vixen/
config.rs1use clap::Args;
3use serde::Deserialize;
4pub trait MaybeDefault: Sized {
7 fn default_opt() -> Option<Self>;
9}
10
11impl<T: Default> MaybeDefault for T {
12 #[inline]
13 fn default_opt() -> Option<Self> { Some(Self::default()) }
14}
15
16#[derive(Debug, Args)]
18pub struct VixenConfig<S>
19where S: Args
20{
21 #[command(flatten)]
23 pub source: S,
24
25 #[command(flatten)]
27 pub buffer: BufferConfig,
28}
29
30impl<'de, S> Deserialize<'de> for VixenConfig<S>
31where S: Args + Deserialize<'de>
32{
33 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
34 where D: serde::Deserializer<'de> {
35 #[derive(Deserialize)]
36 #[serde(bound = "S: Deserialize<'de>")]
37 struct Inner<S> {
38 source: S,
39 #[serde(default)]
40 buffer: BufferConfig,
41 }
42
43 let Inner { source, buffer } = Inner::<S>::deserialize(deserializer)?;
44
45 Ok(Self { source, buffer })
46 }
47}
48
49#[derive(Debug, Clone, Copy, clap::Args, serde::Deserialize)]
51#[serde(rename_all = "kebab-case")]
52pub struct BufferConfig {
53 #[arg(long, env)]
56 pub jobs: Option<usize>,
57 #[arg(long, env)]
60 pub sources_channel_size: usize,
61}
62
63impl Default for BufferConfig {
64 fn default() -> Self {
65 Self {
66 jobs: None,
67 sources_channel_size: 100,
68 }
69 }
70}
71
72#[derive(
74 Default,
75 Debug,
76 Clone,
77 Copy,
78 PartialEq,
79 Eq,
80 PartialOrd,
81 Ord,
82 Hash,
83 clap::Args,
84 serde::Deserialize,
85)]
86pub struct NullConfig;
87
88impl From<Option<NullConfig>> for NullConfig {
89 #[inline]
90 fn from(value: Option<NullConfig>) -> Self { value.unwrap_or_default() }
91}
92
93#[derive(Debug, serde::Deserialize)]
95#[repr(transparent)]
96pub struct OptConfig<T>(Option<T>);
97
98impl<T> Default for OptConfig<T> {
99 #[inline]
100 fn default() -> Self { Self(None) }
101}
102
103impl<T> OptConfig<T> {
104 #[inline]
106 pub fn opt(self) -> Option<T> { self.into() }
107}
108
109impl<T> From<T> for OptConfig<T> {
110 #[inline]
111 fn from(value: T) -> Self { Some(value).into() }
112}
113
114impl<T> From<Option<T>> for OptConfig<T> {
115 #[inline]
116 fn from(value: Option<T>) -> Self { Self(value) }
117}
118
119impl<T> From<OptConfig<T>> for Option<T> {
120 #[inline]
121 fn from(OptConfig(value): OptConfig<T>) -> Self { value }
122}
123
124impl<T> std::ops::Deref for OptConfig<T> {
125 type Target = Option<T>;
126
127 #[inline]
128 fn deref(&self) -> &Self::Target { &self.0 }
129}
130
131impl<T> std::ops::DerefMut for OptConfig<T> {
132 #[inline]
133 fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
134}
135
136impl<T: clap::FromArgMatches> clap::FromArgMatches for OptConfig<T> {
137 fn from_arg_matches(matches: &clap::ArgMatches) -> Result<Self, clap::Error> {
138 T::from_arg_matches(matches).map(Into::into)
139 }
140
141 fn from_arg_matches_mut(matches: &mut clap::ArgMatches) -> Result<Self, clap::Error> {
142 T::from_arg_matches(matches).map(Into::into)
143 }
144
145 fn update_from_arg_matches(&mut self, matches: &clap::ArgMatches) -> Result<(), clap::Error> {
146 self.0
147 .as_mut()
148 .expect("Cannot update empty OptConfig")
149 .update_from_arg_matches(matches)
150 }
151
152 fn update_from_arg_matches_mut(
153 &mut self,
154 matches: &mut clap::ArgMatches,
155 ) -> Result<(), clap::Error> {
156 self.0
157 .as_mut()
158 .expect("Cannot update empty OptConfig")
159 .update_from_arg_matches_mut(matches)
160 }
161}
162
163impl<T: clap::Args> clap::Args for OptConfig<T> {
164 fn group_id() -> Option<clap::Id> { T::group_id() }
165
166 fn augment_args(cmd: clap::Command) -> clap::Command { T::augment_args(cmd) }
167
168 fn augment_args_for_update(cmd: clap::Command) -> clap::Command {
169 T::augment_args_for_update(cmd)
170 }
171}
172
173#[allow(dead_code)] fn update_clone<T: ToOwned, U: Into<T>, F: FnOnce(&mut U) -> V, V>(t: &mut T, f: F) -> V
176where T::Owned: Into<U> {
177 let mut u = t.to_owned().into();
178 let ret = f(&mut u);
179 *t = u.into();
180 ret
181}