hyper_simple_server/
cli.rs

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					// NOP
315				} 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					// NOP
326				}
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