1use std::process::Child;
2use std::process::Output;
3
4pub trait ParameterizedSpawn<T> {
5 type Output;
6 type Error;
7
8 fn spawn_with(&mut self, input: T) -> Result<Self::Output, Self::Error>;
9}
10
11pub trait ParameterizedOutput<T> {
12 type Error;
13
14 fn output_with(&mut self, input: T) -> Result<Output, Self::Error>;
15}
16
17impl<T, I> ParameterizedOutput<I> for T
18where
19 T: ParameterizedSpawn<I, Output = Child, Error = std::io::Error>,
20{
21 type Error = std::io::Error;
22
23 fn output_with(&mut self, input: I) -> Result<Output, Self::Error> {
24 self.spawn_with(input)
25 .and_then(|child| child.wait_with_output())
26 }
27}
28
29pub trait SpawnExt: ParameterizedSpawn<()> {
30 fn spawn(&mut self) -> Result<Self::Output, Self::Error>;
31}
32
33impl<T> SpawnExt for T
34where
35 T: ParameterizedSpawn<()>,
36{
37 fn spawn(&mut self) -> Result<Self::Output, Self::Error> {
38 self.spawn_with(())
39 }
40}
41
42pub trait OutputExt: SpawnExt {
43 fn output(&mut self) -> Result<Output, Self::Error>;
44}
45
46impl<T> OutputExt for T
47where
48 T: SpawnExt<Output = Child, Error = std::io::Error>,
49{
50 fn output(&mut self) -> Result<Output, Self::Error> {
51 self.spawn().and_then(|child| child.wait_with_output())
52 }
53}
54
55macro_rules! spawnext_def {
62 (
63 $spawn_trait:ident,
64 $output_trait:ident,
65 $($param:ident : $T:ident),+
66 ) => {
67 #[allow(clippy::too_many_arguments)]
68 #[allow(unused_parens)]
69 pub trait $spawn_trait<$($T),+>: ParameterizedSpawn<($($T,)+)> {
70 fn spawn(
71 &mut self,
72 $($param: $T),+
73 ) -> Result<Self::Output, Self::Error>;
74 }
75
76 #[allow(clippy::too_many_arguments)]
77 #[allow(unused_parens)]
78 impl<T, $($T),+> $spawn_trait<$($T),+> for T
79 where
80 T: ParameterizedSpawn<($($T,)+)>,
81 {
82 fn spawn(
83 &mut self,
84 $($param: $T),+
85 ) -> Result<Self::Output, Self::Error> {
86 self.spawn_with(($($param,)+))
87 }
88 }
89
90 #[allow(clippy::too_many_arguments)]
91 #[allow(unused_parens)]
92 pub trait $output_trait<$($T),+>: $spawn_trait<$($T),+> {
93 fn output(
94 &mut self,
95 $($param: $T),+
96 ) -> Result<Output, Self::Error>;
97 }
98
99 #[allow(clippy::too_many_arguments)]
100 #[allow(unused_parens)]
101 impl<T, $($T),+> $output_trait<$($T),+> for T
102 where
103 T: $spawn_trait<$($T),+, Output = std::process::Child, Error = std::io::Error>,
104 {
105 fn output(
106 &mut self,
107 $($param: $T),+
108 ) -> Result<Output, Self::Error> {
109 self.spawn($($param),+).and_then(|child| child.wait_with_output())
110 }
111 }
112 };
113}
114
115spawnext_def!(SpawnExt1, OutputExt1, a: T1);
116spawnext_def!(SpawnExt2, OutputExt2, a: T1, b: T2);
117spawnext_def!(SpawnExt3, OutputExt3, a: T1, b: T2, c: T3);
118spawnext_def!(SpawnExt4, OutputExt4, a: T1, b: T2, c: T3, d: T4);
119spawnext_def!(SpawnExt5, OutputExt5, a: T1, b: T2, c: T3, d: T4, e: T5);
120spawnext_def!(SpawnExt6, OutputExt6, a: T1, b: T2, c: T3, d: T4, e: T5, f: T6);
121spawnext_def!(SpawnExt7, OutputExt7, a: T1, b: T2, c: T3, d: T4, e: T5, f: T6, g: T7);
122spawnext_def!(SpawnExt8, OutputExt8, a: T1, b: T2, c: T3, d: T4, e: T5, f: T6, g: T7, h: T8);