1use super::{L2rUser, Options, Result};
2use super::{PeerConstructor, ProgramState};
3use std;
4use std::cell::RefCell;
5use std::rc::Rc;
6
7pub enum ClassMessageBoundaryStatus {
8 StreamOriented,
9 MessageOriented,
10 MessageBoundaryStatusDependsOnInnerType,
11}
12
13pub enum ClassMulticonnectStatus {
14 MultiConnect,
15 SingleConnect,
16 MulticonnectnessDependsOnInnerType,
17}
18
19pub trait SpecifierClass: std::fmt::Debug {
23 fn get_name(&self) -> &'static str;
25 fn get_prefixes(&self) -> Vec<&'static str>;
27 fn help(&self) -> &'static str;
29 fn construct(&self, arg: &str) -> Result<Rc<dyn Specifier>>;
32 fn construct_overlay(&self, inner: Rc<dyn Specifier>) -> Result<Rc<dyn Specifier>>;
34 fn is_overlay(&self) -> bool;
36 fn message_boundary_status(&self) -> ClassMessageBoundaryStatus;
38
39 fn multiconnect_status(&self) -> ClassMulticonnectStatus;
40 fn alias_info(&self) -> Option<&'static str>;
42}
43
44macro_rules! specifier_alias {
45 (name=$n:ident,
46 prefixes=[$($p:expr),*],
47 alias=$x:expr,
48 help=$h:expr) => {
49 #[derive(Debug,Default)]
50 pub struct $n;
51 impl $crate::SpecifierClass for $n {
52 fn get_name(&self) -> &'static str { stringify!($n) }
53 fn get_prefixes(&self) -> Vec<&'static str> { vec![$($p),*] }
54 fn help(&self) -> &'static str { $h }
55 fn message_boundary_status(&self) -> $crate::ClassMessageBoundaryStatus {
56 panic!("Error: message_boundary_status called on alias class")
57 }
58 fn multiconnect_status(&self) -> $crate::ClassMulticonnectStatus {
59 panic!("Error: multiconnect_status called on alias class")
60 }
61 fn is_overlay(&self) -> bool {
62 false
63 }
64 fn construct(&self, _arg:&str) -> $crate::Result<Rc<dyn Specifier>> {
65 panic!("Error: construct called on alias class")
66 }
67 fn construct_overlay(&self, _inner : Rc<dyn Specifier>) -> $crate::Result<Rc<dyn Specifier>> {
68 panic!("Error: construct_overlay called on alias class")
69 }
70 fn alias_info(&self) -> Option<&'static str> { Some($x) }
71 }
72 };
73}
74
75macro_rules! specifier_class {
76 (name=$n:ident,
77 target=$t:ident,
78 prefixes=[$($p:expr),*],
79 arg_handling=$c:tt,
80 overlay=$o:expr,
81 $so:expr,
82 $ms:expr,
83 help=$h:expr) => {
84 #[derive(Debug,Default)]
85 pub struct $n;
86 impl $crate::SpecifierClass for $n {
87 fn get_name(&self) -> &'static str { stringify!($n) }
88 fn get_prefixes(&self) -> Vec<&'static str> { vec![$($p),*] }
89 fn help(&self) -> &'static str { $h }
90 fn message_boundary_status(&self) -> $crate::ClassMessageBoundaryStatus {
91 use $crate::ClassMessageBoundaryStatus::*;
92 $so
93 }
94 fn multiconnect_status(&self) -> $crate::ClassMulticonnectStatus {
95 use $crate::ClassMulticonnectStatus::*;
96 $ms
97 }
98 fn is_overlay(&self) -> bool {
99 $o
100 }
101 specifier_class!(construct target=$t $c);
102 }
103 };
104 (construct target=$t:ident noarg) => {
105 fn construct(&self, just_arg:&str) -> $crate::Result<Rc<dyn Specifier>> {
106 if just_arg != "" {
107 Err(format!("{}-specifer requires no parameters. `{}` is not needed",
108 self.get_name(), just_arg))?;
109 }
110 Ok(Rc::new($t))
111 }
112 fn construct_overlay(&self, _inner : Rc<dyn Specifier>) -> $crate::Result<Rc<dyn Specifier>> {
113 panic!("Error: construct_overlay called on non-overlay specifier class")
114 }
115 fn alias_info(&self) -> Option<&'static str> { None }
116 };
117 (construct target=$t:ident into) => {
118 fn construct(&self, just_arg:&str) -> $crate::Result<Rc<dyn Specifier>> {
119 Ok(Rc::new($t(just_arg.into())))
120 }
121 fn construct_overlay(&self, _inner : Rc<dyn Specifier>) -> $crate::Result<Rc<dyn Specifier>> {
122 panic!("Error: construct_overlay called on non-overlay specifier class")
123 }
124 fn alias_info(&self) -> Option<&'static str> { None }
125 };
126 (construct target=$t:ident parse) => {
127 fn construct(&self, just_arg:&str) -> $crate::Result<Rc<dyn Specifier>> {
128 Ok(Rc::new($t(just_arg.parse()?)))
129 }
130 fn construct_overlay(&self, _inner : Rc<dyn Specifier>) -> $crate::Result<Rc<dyn Specifier>> {
131 panic!("Error: construct_overlay called on non-overlay specifier class")
132 }
133 fn alias_info(&self) -> Option<&'static str> { None }
134 };
135 (construct target=$t:ident parseresolve) => {
136 fn construct(&self, just_arg:&str) -> $crate::Result<Rc<dyn Specifier>> {
137 use std::net::ToSocketAddrs;
138 info!("Resolving hostname to IP addresses");
139 let addrs : Vec<std::net::SocketAddr> = just_arg.to_socket_addrs()?.collect();
140 if addrs.is_empty() {
141 Err("Failed to resolve this hostname to IP")?;
142 }
143 for addr in &addrs {
144 info!("Got IP: {}", addr);
145 }
146 Ok(Rc::new($t(addrs)))
147 }
148 fn construct_overlay(&self, _inner : Rc<dyn Specifier>) -> $crate::Result<Rc<dyn Specifier>> {
149 panic!("Error: construct_overlay called on non-overlay specifier class")
150 }
151 fn alias_info(&self) -> Option<&'static str> { None }
152 };
153 (construct target=$t:ident subspec) => {
154 fn construct(&self, just_arg:&str) -> $crate::Result<Rc<dyn Specifier>> {
155 Ok(Rc::new($t($crate::spec(just_arg)?)))
156 }
157 fn construct_overlay(&self, _inner : Rc<dyn Specifier>) -> $crate::Result<Rc<dyn Specifier>> {
158 Ok(Rc::new($t(_inner)))
159 }
160 fn alias_info(&self) -> Option<&'static str> { None }
161 };
162 (construct target=$t:ident {$($x:tt)*}) => {
163 $($x)*
164 fn alias_info(&self) -> Option<&'static str> { None }
165 };
166}
167
168
169#[derive(Debug)]
170pub struct SpecifierNode {
171 pub cls: Rc<dyn SpecifierClass>,
172 }
174
175#[derive(Debug)]
176pub struct SpecifierStack {
177 pub addr: String,
178 pub addrtype: SpecifierNode,
179 pub overlays: Vec<SpecifierNode>,
180}
181
182#[derive(Clone)]
183pub struct ConstructParams {
184 pub global_state: Rc<RefCell<ProgramState>>,
185 pub program_options: Rc<Options>,
186 pub left_to_right: L2rUser,
187}
188
189impl ConstructParams {
191 pub fn reset_l2r(&mut self) {
193 match self.left_to_right {
194 L2rUser::FillIn(ref mut x) => {
195 *x.borrow_mut() = Default::default();
196 }
198 L2rUser::ReadFrom(_) => panic!("ConstructParams::reset_l2r called wrong"),
199 }
200 }
201 pub fn reply(&self) -> Self {
206 let l2r = match self.left_to_right {
207 L2rUser::FillIn(ref x) => Rc::new(x.borrow().clone()),
208 L2rUser::ReadFrom(_) => panic!("ConstructParams::reply called wrong"),
209 };
210 ConstructParams {
211 global_state: self.global_state.clone(),
212 program_options: self.program_options.clone(),
213 left_to_right: L2rUser::ReadFrom(l2r),
214 }
215 }
216
217 pub fn deep_clone(&self) -> Self {
218 let l2r = match self.left_to_right {
219 L2rUser::FillIn(ref x) => L2rUser::FillIn(Rc::new(RefCell::new(x.borrow().clone()))),
220 L2rUser::ReadFrom(_) => {
221 panic!(
222 "You are not supposed to use ConstructParams::deep_clone on ReadFrom things"
223 );
224 }
225 };
226 ConstructParams {
227 global_state: self.global_state.clone(),
228 program_options: self.program_options.clone(),
229 left_to_right: l2r,
230 }
231 }
232
233 pub fn global<T:std::any::Any, F>(&self, def:F) -> std::cell::RefMut<T>
235 where F : FnOnce()->T
236 {
237 std::cell::RefMut::map(
238 self.global_state.borrow_mut(),
239 |x|{
240 x.0.entry::<T>().or_insert_with(def)
241 }
242 )
243 }
244}
245
246pub trait Specifier: std::fmt::Debug {
250 fn construct(&self, p: ConstructParams) -> PeerConstructor;
252
253 fn is_multiconnect(&self) -> bool;
255 fn uses_global_state(&self) -> bool;
256}
257
258impl Specifier for Rc<dyn Specifier> {
259 fn construct(&self, p: ConstructParams) -> PeerConstructor {
260 (**self).construct(p)
261 }
262
263 fn is_multiconnect(&self) -> bool {
264 (**self).is_multiconnect()
265 }
266 fn uses_global_state(&self) -> bool {
267 (**self).uses_global_state()
268 }
269}
270
271macro_rules! specifier_boilerplate {
272 (singleconnect $($e:tt)*) => {
273 fn is_multiconnect(&self) -> bool { false }
274 specifier_boilerplate!($($e)*);
275 };
276 (multiconnect $($e:tt)*) => {
277 fn is_multiconnect(&self) -> bool { true }
278 specifier_boilerplate!($($e)*);
279 };
280 (no_subspec $($e:tt)*) => {
281 specifier_boilerplate!($($e)*);
282 };
283 (has_subspec $($e:tt)*) => {
284 specifier_boilerplate!($($e)*);
285 };
286 () => {
287 };
288 (globalstate $($e:tt)*) => {
289 fn uses_global_state(&self) -> bool { true }
290 specifier_boilerplate!($($e)*);
291 };
292 (noglobalstate $($e:tt)*) => {
293 fn uses_global_state(&self) -> bool { false }
294 specifier_boilerplate!($($e)*);
295 };
296}
297
298macro_rules! self_0_is_subspecifier {
299 (...) => {
300 };
302 (proxy_is_multiconnect) => {
303 self_0_is_subspecifier!(...);
304 fn is_multiconnect(&self) -> bool { self.0.is_multiconnect() }
305 };
306}