1
2
3use crate::prelude::*;
4
5
6
7
8#[ derive (Default) ]
9#[ cfg (feature = "hss-config") ]
10#[ cfg (feature = "hss-cli") ]
11pub struct ConfigurationArguments {
12
13 pub endpoint_socket_address : Option<String>,
14 pub endpoint_socket_address_help : String,
15
16 #[ cfg (unix) ]
17 pub endpoint_descriptor : Option<u32>,
18 #[ cfg (unix) ]
19 pub endpoint_descriptor_help : String,
20
21 #[ cfg (feature = "hyper--server-http1") ]
22 pub endpoint_protocol_http1 : Option<bool>,
23 #[ cfg (feature = "hyper--server-http1") ]
24 pub endpoint_protocol_http1_help : String,
25 #[ cfg (feature = "hyper--server-http2") ]
26 pub endpoint_protocol_http2 : Option<bool>,
27 #[ cfg (feature = "hyper--server-http2") ]
28 pub endpoint_protocol_http2_help : String,
29
30 #[ cfg (feature = "hss-tls-any") ]
31 pub endpoint_insecure : Option<bool>,
32 #[ cfg (feature = "hss-tls-any") ]
33 pub endpoint_insecure_help : String,
34
35 #[ cfg (feature = "hss-tls-rust") ]
36 pub endpoint_rust_tls_certificate_pem_path : Option<String>,
37 #[ cfg (feature = "hss-tls-rust") ]
38 pub endpoint_rust_tls_certificate_pem_path_help : String,
39 #[ cfg (feature = "hss-tls-rust") ]
40 pub endpoint_rust_tls_certificate_fallback : Option<RustTlsCertificate>,
41
42 #[ cfg (feature = "hss-tls-native") ]
43 pub endpoint_native_tls_certificate_pkcs12_path : Option<String>,
44 #[ cfg (feature = "hss-tls-native") ]
45 pub endpoint_native_tls_certificate_pkcs12_password : Option<String>,
46 #[ cfg (feature = "hss-tls-native") ]
47 pub endpoint_native_tls_certificate_pkcs12_path_help : String,
48 #[ cfg (feature = "hss-tls-native") ]
49 pub endpoint_native_tls_certificate_fallback : Option<NativeTlsCertificate>,
50
51 #[ cfg (feature = "hss-server-mt") ]
52 pub server_threads : Option<usize>,
53 #[ cfg (feature = "hss-server-mt") ]
54 pub server_threads_help : String,
55
56 #[ cfg (feature = "hss-server-profiling") ]
57 pub server_profiling : Option<String>,
58 #[ cfg (feature = "hss-server-profiling") ]
59 pub server_profiling_help : String,
60}
61
62
63
64
65#[ cfg (feature = "hss-config") ]
66#[ cfg (feature = "hss-cli") ]
67impl ConfigurationArguments {
68
69 pub fn with_defaults (_configuration : &Configuration) -> ServerResult<Self> {
70
71 let mut _arguments = Self::default ();
72
73 match _configuration.endpoint.address {
74 EndpointAddress::Socket (_address) =>
75 _arguments.endpoint_socket_address = Some (_address.to_string ()),
76 #[ cfg (unix) ]
77 EndpointAddress::Descriptor (_descriptor) =>
78 _arguments.endpoint_descriptor = Some (_descriptor),
79 }
80
81 match _configuration.endpoint.protocol {
82 #[ cfg (feature = "hyper--server-http1") ]
83 EndpointProtocol::Http1 =>
84 _arguments.endpoint_protocol_http1 = Some (true),
85 #[ cfg (feature = "hyper--server-http2") ]
86 EndpointProtocol::Http2 =>
87 _arguments.endpoint_protocol_http2 = Some (true),
88 #[ cfg (feature = "hyper--server-http1") ]
89 #[ cfg (feature = "hyper--server-http2") ]
90 EndpointProtocol::Http12 => {
91 _arguments.endpoint_protocol_http1 = Some (true);
92 _arguments.endpoint_protocol_http2 = Some (true);
93 }
94 EndpointProtocol::Generic =>
95 (),
96 }
97
98 #[ cfg (feature = "hss-tls-any") ]
99 match _configuration.endpoint.security {
100 EndpointSecurity::Insecure =>
101 _arguments.endpoint_insecure = Some (true),
102 #[ cfg (feature = "hss-tls-rust") ]
103 EndpointSecurity::RustTls (ref _certificate) => {
104 _arguments.endpoint_insecure = Some (false);
105 _arguments.endpoint_rust_tls_certificate_fallback = Some (_certificate.clone ());
106 }
107 #[ cfg (feature = "hss-tls-native") ]
108 EndpointSecurity::NativeTls (ref _certificate) => {
109 _arguments.endpoint_insecure = Some (false);
110 _arguments.endpoint_native_tls_certificate_fallback = Some (_certificate.clone ());
111 }
112 }
113
114 #[ cfg (feature = "hss-server-mt") ]
115 {
116 _arguments.server_threads = _configuration.threads;
117 }
118
119 #[ cfg (feature = "hss-server-profiling") ]
120 if let Some (_path) = _configuration.profiling.as_ref () {
121 let _path = _path.to_str () .or_wrap (0xd708ca76) ?;
122 _arguments.server_profiling = Some (_path.to_owned ());
123 }
124
125 Ok (_arguments)
126 }
127
128
129 #[ allow (single_use_lifetimes) ]
130 pub fn prepare <'a> (&'a mut self, _parser : &mut argparse::ArgumentParser<'a>) -> () {
131
132 self.endpoint_socket_address_help = self.endpoint_socket_address.as_ref () .map_or_else (
133 || format! ("listen on TCP socket address"),
134 |_address| format! ("listen on TCP socket address (default `{}`)", _address));
135 let mut _argument = _parser.refer (&mut self.endpoint_socket_address);
136 {
137 _argument
138 .metavar ("<socket-address>")
139 .add_option (&["--listen-address"], argparse::StoreOption, &self.endpoint_socket_address_help)
140 .add_option (&["--listen-any-80"], argparse::StoreConst (Some (String::from ("0.0.0.0:80"))), "listen on any IP with port 80 (might require root or capabilities)")
141 .add_option (&["--listen-any-8080"], argparse::StoreConst (Some (String::from ("0.0.0.0:8080"))), "listen on any IP with port 8080")
142 .add_option (&["--listen-localhost-8080"], argparse::StoreConst (Some (String::from ("127.0.0.1:8080"))), "listen on localhost with port 8080");
143 }
144 #[ cfg (feature = "hss-tls-any") ]
145 {
146 _argument
147 .add_option (&["--listen-any-443"], argparse::StoreConst (Some (String::from ("0.0.0.0:443"))), "listen on any IP with port 443 (might require root or capabilities)")
148 .add_option (&["--listen-any-8443"], argparse::StoreConst (Some (String::from ("0.0.0.0:8443"))), "listen on any IP with port 8443")
149 .add_option (&["--listen-localhost-8443"], argparse::StoreConst (Some (String::from ("127.0.0.1:8443"))), "listen on localhost with port 8443")
150 ;
151 }
152
153 #[ cfg (unix) ]
154 {
155 self.endpoint_descriptor_help = self.endpoint_descriptor.as_ref () .map_or_else (
156 || format! ("listen on TCP socket with descriptor"),
157 |_descriptor| format! ("listen on TCP socket with descriptor (default `{}`)", _descriptor));
158 _parser.refer (&mut self.endpoint_descriptor)
159 .metavar ("<socket-descriptor>")
160 .add_option (&["--listen-descriptor"], argparse::StoreOption, &self.endpoint_descriptor_help);
161 }
162
163 #[ cfg (feature = "hyper--server-http1") ]
164 {
165 self.endpoint_protocol_http1_help = self.endpoint_protocol_http1.as_ref () .map_or_else (
166 || format! ("enable HTTP/1 support"),
167 |_enabled| format! ("enable HTTP/1 support (default `{}`)", _enabled));
168 _parser.refer (&mut self.endpoint_protocol_http1)
169 .add_option (&["--enable-http1"], argparse::StoreConst (Some (true)), &self.endpoint_protocol_http1_help)
170 .add_option (&["--disable-http1"], argparse::StoreConst (Some (false)), "");
171 }
172
173 #[ cfg (feature = "hyper--server-http2") ]
174 {
175 self.endpoint_protocol_http2_help = self.endpoint_protocol_http2.as_ref () .map_or_else (
176 || format! ("enable HTTP/2 support"),
177 |_enabled| format! ("enable HTTP/2 support (default `{}`)", _enabled));
178 _parser.refer (&mut self.endpoint_protocol_http2)
179 .add_option (&["--enable-http2"], argparse::StoreConst (Some (true)), &self.endpoint_protocol_http2_help)
180 .add_option (&["--disable-http2"], argparse::StoreConst (Some (false)), "");
181 }
182
183 #[ cfg (feature = "hss-tls-any") ]
184 {
185 self.endpoint_insecure_help = if self.endpoint_insecure.unwrap_or (false) {
186 format! ("disable TLS support (default disabled)")
187 } else {
188 format! ("disable TLS support (default enabled)")
189 };
190 _parser.refer (&mut self.endpoint_insecure)
191 .add_option (&["--disable-tls"], argparse::StoreConst (Some (true)), &self.endpoint_insecure_help)
192 .add_option (&["--enable-tls"], argparse::StoreConst (Some (false)), "");
193 }
194
195 #[ cfg (feature = "hss-tls-rust") ]
196 {
197 let _endpoint_has_certificate_fallback = self.endpoint_rust_tls_certificate_fallback.is_some ();
198 self.endpoint_rust_tls_certificate_pem_path_help = self.endpoint_rust_tls_certificate_pem_path.as_ref () .map_or_else (
199 || if _endpoint_has_certificate_fallback {
200 format! ("load TLS certificate in PEM format (with Rust TLS library) from path (default embedded in binary)")
201 } else {
202 format! ("load TLS certificate in PEM format (with Rust TLS library) from path")
203 },
204 |_path| format! ("load TLS certificate in PEM format (with Rust TLS library) from path (default `{}`)", _path));
205 _parser.refer (&mut self.endpoint_rust_tls_certificate_pem_path)
206 .metavar ("<path>")
207 .add_option (&["--load-rust-tls-pem-path"], argparse::StoreOption, &self.endpoint_rust_tls_certificate_pem_path_help);
208 }
209
210 #[ cfg (feature = "hss-tls-native") ]
211 {
212 let _endpoint_has_certificate_fallback = self.endpoint_native_tls_certificate_fallback.is_some ();
213 self.endpoint_native_tls_certificate_pkcs12_path_help = self.endpoint_native_tls_certificate_pkcs12_path.as_ref () .map_or_else (
214 || if _endpoint_has_certificate_fallback {
215 format! ("load TLS certificate in PKCS#12 format (with native TLS library) from path (default embedded in binary)")
216 } else {
217 format! ("load TLS certificate in PKCS#12 format (with native TLS library) from path")
218 },
219 |_path| format! ("load TLS certificate in PKCS#12 format (with native TLS library) from path (default `{}`)", _path));
220 _parser.refer (&mut self.endpoint_native_tls_certificate_pkcs12_path)
221 .metavar ("<path>")
222 .add_option (&["--load-native-tls-pkcs12-path"], argparse::StoreOption, &self.endpoint_native_tls_certificate_pkcs12_path_help);
223 _parser.refer (&mut self.endpoint_native_tls_certificate_pkcs12_password)
224 .metavar ("<password>")
225 .add_option (&["--load-native-tls-pkcs12-password"], argparse::StoreOption, "");
226 }
227
228 #[ cfg (feature = "hss-server-mt") ]
229 {
230 self.server_threads_help = self.server_threads.as_ref () .map_or_else (
231 || format! ("enable server multi-threading"),
232 |_threads| format! ("enable server multi-threading (default `{}` threads)", _threads));
233 _parser.refer (&mut self.server_threads)
234 .metavar ("<server-threads>")
235 .add_option (&["--server-threads"], argparse::StoreOption, &self.server_threads_help)
236 .add_option (&["--no-server-threads"], argparse::StoreConst (None), "");
237 }
238
239 #[ cfg (feature = "hss-server-profiling") ]
240 {
241 self.server_profiling_help = self.server_profiling.as_ref () .map_or_else (
242 || format! ("enable server profiling"),
243 |_profiling| format! ("enable server profiling (default `{}` path)", _profiling));
244 _parser.refer (&mut self.server_profiling)
245 .metavar ("<server-profiling>")
246 .add_option (&["--server-profiling"], argparse::StoreOption, &self.server_profiling_help)
247 .add_option (&["--no-server-profiling"], argparse::StoreConst (None), "");
248 }
249 }
250
251
252 pub fn update (&self, _configuration : &mut Configuration) -> ServerResult {
253
254 #[ cfg (unix) ]
255 if self.endpoint_socket_address.is_some () && self.endpoint_descriptor.is_some () {
256 return Err (error_with_message (0xbb9b6c08, "conflicting TCP listen options specified"));
257 }
258
259 if let Some (_address) = self.endpoint_socket_address.as_ref () {
260 _configuration.endpoint.address = EndpointAddress::from_socket_address_parse (_address) ?;
261 }
262 #[ cfg (unix) ]
263 if let Some (_descriptor) = self.endpoint_descriptor {
264 _configuration.endpoint.address = EndpointAddress::from_descriptor (_descriptor);
265 }
266
267 #[ cfg (feature = "hyper--server-http") ]
268 {
269 let mut _http1_enabled = _configuration.endpoint.protocol.supports_http1 ();
270 #[ cfg (feature = "hyper--server-http1") ]
271 if let Some (_enabled) = self.endpoint_protocol_http1 {
272 _http1_enabled = _enabled;
273 }
274 let mut _http2_enabled = _configuration.endpoint.protocol.supports_http2 ();
275 #[ cfg (feature = "hyper--server-http2") ]
276 if let Some (_enabled) = self.endpoint_protocol_http2 {
277 _http2_enabled = _enabled;
278 }
279 _configuration.endpoint.protocol = EndpointProtocol::with_http_support (_http1_enabled, _http2_enabled);
280 }
281
282 #[ cfg (feature = "hss-tls-any") ]
283 if let Some (true) = self.endpoint_insecure {
284 _configuration.endpoint.security = EndpointSecurity::Insecure;
285 }
286
287 #[ cfg (feature = "hss-tls-rust") ]
288 #[ cfg (feature = "hss-tls-native") ]
289 if self.endpoint_rust_tls_certificate_pem_path.is_some () && self.endpoint_native_tls_certificate_pkcs12_path.is_some () {
290 return Err (error_with_message (0x7ce8d799, "conflicting load TLS certificate options specified"));
291 }
292 #[ cfg (feature = "hss-tls-rust") ]
293 if let Some (_path) = self.endpoint_rust_tls_certificate_pem_path.as_ref () {
294 _configuration.endpoint.security = EndpointSecurity::RustTls (RustTlsCertificate::load_from_pem_file (_path) ?);
295 } else if let Some (_certificate) = self.endpoint_rust_tls_certificate_fallback.as_ref () {
296 if let Some (false) = self.endpoint_insecure {
297 _configuration.endpoint.security = EndpointSecurity::RustTls (_certificate.clone ());
298 }
299 }
300 #[ cfg (feature = "hss-tls-native") ]
301 if let Some (_path) = self.endpoint_native_tls_certificate_pkcs12_path.as_ref () {
302 let _password = self.endpoint_native_tls_certificate_pkcs12_password.as_ref () .map_or_else (|| "", String::as_str);
303 _configuration.endpoint.security = EndpointSecurity::NativeTls (NativeTlsCertificate::load_from_pkcs12_file (_path, _password) ?);
304 } else if let Some (_certificate) = self.endpoint_native_tls_certificate_fallback.as_ref () {
305 if let Some (false) = self.endpoint_insecure {
306 _configuration.endpoint.security = EndpointSecurity::NativeTls (_certificate.clone ());
307 }
308 }
309
310 #[ cfg (feature = "hss-tls-any") ]
311 if let Some (_endpoint_insecure) = self.endpoint_insecure {
312 if _endpoint_insecure {
313 if let EndpointSecurity::Insecure = _configuration.endpoint.security {
314 } else {
316 return Err (error_with_message (0x1111c2cc, "conflicting insecure and load TLS certificate options"));
317 }
318 } else {
319 if let EndpointSecurity::Insecure = _configuration.endpoint.security {
320 #[ cfg (feature = "hss-tls-any") ]
321 return Err (error_with_message (0x6621c453, "conflicting secure and missing load TLS certificate options"));
322 #[ cfg (not (feature = "hss-tls-any")) ]
323 return Err (error_with_message (0x0e0edc6a, "conflicting secure and unavailable TLS engine options"));
324 } else {
325 }
327 }
328 }
329
330 #[ cfg (feature = "hss-server-mt") ]
331 {
332 _configuration.threads = self.server_threads;
333 }
334
335 #[ cfg (feature = "hss-server-profiling") ]
336 {
337 _configuration.profiling = self.server_profiling.as_ref () .map (|_path| path::PathBuf::from (_path));
338 }
339
340 Ok (())
341 }
342
343
344 pub fn parse (_configuration : Configuration, _arguments : Option<CliArguments>) -> ServerResult<Configuration> {
345 Self::parse_with_extensions (_configuration, (), _arguments)
346 }
347
348 pub fn parse_with_extensions (mut _configuration : Configuration, mut _extensions : impl CliExtensions, _arguments : Option<CliArguments>) -> ServerResult<Configuration> {
349
350 let _arguments = CliArguments::unwrap_or_args (_arguments);
351 let mut _arguments = _arguments.into_vec_str ();
352 _arguments.insert (0, "<cli>".into ());
353
354 let mut _self = Self::with_defaults (&_configuration) ?;
355
356 {
357 let mut _parser = argparse::ArgumentParser::new ();
358 _self.prepare (&mut _parser);
359 _extensions.prepare (&mut _parser);
360 match _parser.parse (_arguments, &mut io::stdout (), &mut io::stderr ()) {
361 Ok (()) =>
362 (),
363 Err (0) =>
364 ::std::process::exit (0),
365 Err (_code) =>
366 return Err (error_with_message (0x4fec67d5, "invalid arguments!")),
367 }
368 }
369
370 _self.update (&mut _configuration) ?;
371
372 Ok (_configuration)
373 }
374}
375
376
377#[ cfg (feature = "hss-config") ]
378#[ cfg (feature = "hss-cli") ]
379pub trait CliExtensions {
380
381 fn prepare <'a> (self, _parser : &mut argparse::ArgumentParser<'a>) -> () where Self : 'a;
382}
383
384#[ cfg (feature = "hss-config") ]
385#[ cfg (feature = "hss-cli") ]
386impl CliExtensions for () {
387
388 fn prepare <'a> (self, _parser : &mut argparse::ArgumentParser<'a>) -> () where Self : 'a {}
389}
390
391
392#[ cfg (feature = "hss-config") ]
393#[ cfg (feature = "hss-cli") ]
394pub enum CliArgument<'a> {
395 String (&'a mut String, &'static str, &'static str),
396 StringConst (&'a mut String, &'a mut str, &'static str, &'static str),
397 Boolean (&'a mut bool, &'static str, &'static str),
398 BooleanConst (&'a mut bool, bool, &'static str, &'static str),
399}
400
401#[ cfg (feature = "hss-config") ]
402#[ cfg (feature = "hss-cli") ]
403impl CliExtensions for CliArgument<'_> {
404
405 fn prepare <'a> (self, _parser : &mut argparse::ArgumentParser<'a>) -> () where Self : 'a {
406 match self {
407 CliArgument::String (_variable, _flag, _help) => {
408 _parser.refer (_variable) .metavar ("<string>") .add_option (&[_flag], argparse::Store, _help);
409 }
410 CliArgument::StringConst (_variable, _value, _flag, _help) => {
411 _parser.refer (_variable) .metavar ("<string>") .add_option (&[_flag], argparse::StoreConst (_value.into ()), _help);
412 }
413 CliArgument::Boolean (_variable, _flag, _help) => {
414 _parser.refer (_variable) .metavar ("<boolean>") .add_option (&[_flag], argparse::Store, _help);
415 }
416 CliArgument::BooleanConst (_variable, _value, _flag, _help) => {
417 _parser.refer (_variable) .metavar ("<boolean>") .add_option (&[_flag], argparse::StoreConst (_value), _help);
418 }
419 }
420 }
421}
422
423#[ cfg (feature = "hss-config") ]
424#[ cfg (feature = "hss-cli") ]
425impl <const N : usize> CliExtensions for [CliArgument<'_>; N] {
426
427 fn prepare <'a> (self, _parser : &mut argparse::ArgumentParser<'a>) -> () where Self : 'a {
428 for _argument in self {
429 _argument.prepare (_parser);
430 }
431 }
432}
433
434
435
436
437#[ cfg (feature = "hss-cli") ]
438pub struct CliArguments (Vec<OsString>);
439
440#[ cfg (not (feature = "hss-cli")) ]
441pub struct CliArguments {
442 _private : (),
443}
444
445
446#[ cfg (feature = "hss-cli") ]
447impl CliArguments {
448
449 pub fn unwrap_or_args (_arguments : Option<CliArguments>) -> CliArguments {
450 _arguments.unwrap_or_else (CliArguments::from_args)
451 }
452
453 pub fn from_args () -> CliArguments {
454 CliArguments (env::args_os () .into_iter () .skip (1) .collect ())
455 }
456
457 pub fn from_vec_os (_arguments : Vec<OsString>) -> CliArguments {
458 CliArguments (_arguments)
459 }
460
461 pub fn from_vec_str (_arguments : Vec<String>) -> CliArguments {
462 CliArguments::from_vec_os (_arguments.into_iter () .map (OsString::from) .collect ())
463 }
464
465 pub fn into_vec_os (self) -> Vec<OsString> {
466 self.0
467 }
468
469 pub fn into_vec_str (self) -> Vec<String> {
470 self.into_vec_os ()
471 .into_iter ()
472 .map (OsString::into_string)
473 .map (|_result| _result.unwrap_or_else (|_string| _string.to_string_lossy () .into_owned ()))
474 .collect ()
475 }
476
477 pub fn is_empty (&self) -> bool {
478 self.0.is_empty ()
479 }
480
481 pub fn first_os (&self) -> Option<&OsStr> {
482 self.0.first () .map (|_string| _string.as_ref ())
483 }
484
485 pub fn first_str (&self) -> Option<&str> {
486 self.0.first () .and_then (|_string| _string.to_str ())
487 }
488
489 pub fn remove_first_os (&mut self) -> Option<OsString> {
490 if self.0.is_empty () {
491 return None;
492 }
493 Some (self.0.remove (0))
494 }
495
496 pub fn remove_first_str (&mut self) -> Option<String> {
497 self.remove_first_os ()
498 .map (OsString::into_string)
499 .map (|_result| _result.unwrap_or_else (|_string| _string.to_string_lossy () .into_owned ()))
500 }
501
502 pub fn without_first (mut self) -> Self {
503 self.remove_first_os ();
504 self
505 }
506
507 pub fn into_tuple_n_os (self, _length : usize) -> Result<Vec<OsString>, Self> {
508 if self.0.len () == _length {
509 Ok (self.into_vec_os ())
510 } else {
511 Err (self)
512 }
513 }
514
515 pub fn into_tuple_n_str (self, _length : usize) -> Result<Vec<String>, Self> {
516 if self.0.len () == _length {
517 Ok (self.into_vec_str ())
518 } else {
519 Err (self)
520 }
521 }
522
523 pub fn into_tuple_1_os (self) -> Result<(OsString,), Self> {
524 let mut _elements = self.into_tuple_n_os (1) ? .into_iter ();
525 let _tuple = (
526 _elements.next () .infallible (0x0db4f89f),
527 );
528 Ok (_tuple)
529 }
530
531 pub fn into_tuple_1_str (self) -> Result<(String,), Self> {
532 let mut _elements = self.into_tuple_n_str (1) ? .into_iter ();
533 let _tuple = (
534 _elements.next () .infallible (0x3e69a37d),
535 );
536 Ok (_tuple)
537 }
538
539 pub fn into_tuple_2_os (self) -> Result<(OsString, OsString), Self> {
540 let mut _elements = self.into_tuple_n_os (2) ? .into_iter ();
541 let _tuple = (
542 _elements.next () .infallible (0x7303f446),
543 _elements.next () .infallible (0x1d266eeb),
544 );
545 Ok (_tuple)
546 }
547
548 pub fn into_tuple_2_str (self) -> Result<(String, String), Self> {
549 let mut _elements = self.into_tuple_n_str (2) ? .into_iter ();
550 let _tuple = (
551 _elements.next () .infallible (0x8ba4b0b2),
552 _elements.next () .infallible (0x3507fde7),
553 );
554 Ok (_tuple)
555 }
556
557 pub fn into_tuple_3_os (self) -> Result<(OsString, OsString, OsString), Self> {
558 let mut _elements = self.into_tuple_n_os (3) ? .into_iter ();
559 let _tuple = (
560 _elements.next () .infallible (0xdc3beb9b),
561 _elements.next () .infallible (0x90b81bd1),
562 _elements.next () .infallible (0xfb6535ec),
563 );
564 Ok (_tuple)
565 }
566
567 pub fn into_tuple_3_str (self) -> Result<(String, String, String), Self> {
568 let mut _elements = self.into_tuple_n_str (3) ? .into_iter ();
569 let _tuple = (
570 _elements.next () .infallible (0x76903952),
571 _elements.next () .infallible (0xfbb72b5b),
572 _elements.next () .infallible (0x404f94ba),
573 );
574 Ok (_tuple)
575 }
576}
577