@@ -37,6 +37,192 @@ pub enum PipeStage {
3737 Value ( Selector ) ,
3838}
3939
40+ const ALL_SHAPES : & [ OutputShape ] = & [
41+ OutputShape :: Empty ,
42+ OutputShape :: Lines ,
43+ OutputShape :: Rows ,
44+ OutputShape :: Detail ,
45+ OutputShape :: Message ,
46+ OutputShape :: Values ,
47+ OutputShape :: Groups ,
48+ ] ;
49+ const STRUCTURED_SHAPES : & [ OutputShape ] = & [
50+ OutputShape :: Empty ,
51+ OutputShape :: Rows ,
52+ OutputShape :: Detail ,
53+ OutputShape :: Message ,
54+ OutputShape :: Values ,
55+ OutputShape :: Groups ,
56+ ] ;
57+ const COLLECTION_SHAPES : & [ OutputShape ] = & [
58+ OutputShape :: Empty ,
59+ OutputShape :: Lines ,
60+ OutputShape :: Rows ,
61+ OutputShape :: Values ,
62+ OutputShape :: Groups ,
63+ ] ;
64+ const STRUCTURED_COLLECTION_SHAPES : & [ OutputShape ] = & [
65+ OutputShape :: Empty ,
66+ OutputShape :: Rows ,
67+ OutputShape :: Values ,
68+ OutputShape :: Groups ,
69+ ] ;
70+ const PROJECT_SHAPES : & [ OutputShape ] = & [
71+ OutputShape :: Empty ,
72+ OutputShape :: Rows ,
73+ OutputShape :: Detail ,
74+ OutputShape :: Message ,
75+ OutputShape :: Groups ,
76+ ] ;
77+ const GROUP_INPUT_SHAPES : & [ OutputShape ] = & [
78+ OutputShape :: Empty ,
79+ OutputShape :: Rows ,
80+ OutputShape :: Detail ,
81+ OutputShape :: Message ,
82+ OutputShape :: Values ,
83+ ] ;
84+ const GROUPS_ONLY : & [ OutputShape ] = & [ OutputShape :: Groups ] ;
85+ const EMPTY_ONLY : & [ OutputShape ] = & [ OutputShape :: Empty ] ;
86+ const LINES_ONLY : & [ OutputShape ] = & [ OutputShape :: Lines ] ;
87+ const ROWS_ONLY : & [ OutputShape ] = & [ OutputShape :: Rows ] ;
88+ const DETAIL_ONLY : & [ OutputShape ] = & [ OutputShape :: Detail ] ;
89+ const VALUES_ONLY : & [ OutputShape ] = & [ OutputShape :: Values ] ;
90+ const DETAIL_OR_EMPTY : & [ OutputShape ] = & [ OutputShape :: Detail , OutputShape :: Empty ] ;
91+ const MESSAGE_OR_EMPTY : & [ OutputShape ] = & [ OutputShape :: Message , OutputShape :: Empty ] ;
92+ const JQ_OUTPUT_SHAPES : & [ OutputShape ] = & [
93+ OutputShape :: Empty ,
94+ OutputShape :: Rows ,
95+ OutputShape :: Detail ,
96+ OutputShape :: Message ,
97+ OutputShape :: Values ,
98+ ] ;
99+
100+ impl PipeStage {
101+ pub fn name ( & self ) -> & ' static str {
102+ match self {
103+ Self :: Grep ( _) => "F" ,
104+ Self :: ValueSearch ( _) => "V" ,
105+ Self :: KeySearch ( _) => "K" ,
106+ Self :: Truthy ( _) => "?" ,
107+ Self :: Reject ( _) => "reject" ,
108+ Self :: Head { .. } => "L" ,
109+ Self :: Tail ( _) => "tail" ,
110+ Self :: Count => "C" ,
111+ Self :: SortLines { .. } | Self :: SortColumn { .. } => "S" ,
112+ Self :: Columns ( _) => "P" ,
113+ Self :: Group ( _) => "G" ,
114+ Self :: Aggregate ( _) => "A" ,
115+ Self :: CollapseGroups => "Z" ,
116+ Self :: Unroll ( _) => "U" ,
117+ Self :: Jq ( _) => "JQ" ,
118+ Self :: Value ( _) => "VALUE" ,
119+ }
120+ }
121+
122+ pub fn accepted_input_shapes ( & self ) -> & ' static [ OutputShape ] {
123+ match self {
124+ Self :: Grep ( _) | Self :: ValueSearch ( _) | Self :: Reject ( _) | Self :: Count => ALL_SHAPES ,
125+ Self :: KeySearch ( _) | Self :: Truthy ( _) | Self :: Jq ( _) | Self :: Value ( _) => {
126+ STRUCTURED_SHAPES
127+ }
128+ Self :: Head { .. } | Self :: Tail ( _) | Self :: SortLines { .. } => COLLECTION_SHAPES ,
129+ Self :: Columns ( _) => PROJECT_SHAPES ,
130+ Self :: SortColumn { .. } | Self :: Unroll ( _) => STRUCTURED_COLLECTION_SHAPES ,
131+ Self :: Group ( _) => GROUP_INPUT_SHAPES ,
132+ Self :: Aggregate ( _) | Self :: CollapseGroups => GROUPS_ONLY ,
133+ }
134+ }
135+
136+ pub fn resulting_shapes (
137+ & self ,
138+ input : OutputShape ,
139+ ) -> Result < & ' static [ OutputShape ] , PipelineError > {
140+ self . validate_input_shape ( input) ?;
141+ let shapes = match self {
142+ Self :: Grep ( _) | Self :: ValueSearch ( _) | Self :: Reject ( _) => match input {
143+ OutputShape :: Empty => EMPTY_ONLY ,
144+ OutputShape :: Lines => LINES_ONLY ,
145+ OutputShape :: Rows => ROWS_ONLY ,
146+ OutputShape :: Detail => DETAIL_OR_EMPTY ,
147+ OutputShape :: Message => MESSAGE_OR_EMPTY ,
148+ OutputShape :: Values => VALUES_ONLY ,
149+ OutputShape :: Groups => GROUPS_ONLY ,
150+ } ,
151+ Self :: KeySearch ( _) => match input {
152+ OutputShape :: Empty => EMPTY_ONLY ,
153+ OutputShape :: Rows | OutputShape :: Values => ROWS_ONLY ,
154+ OutputShape :: Detail | OutputShape :: Message => DETAIL_OR_EMPTY ,
155+ OutputShape :: Groups => GROUPS_ONLY ,
156+ OutputShape :: Lines => unreachable ! ( "validated input shape" ) ,
157+ } ,
158+ Self :: Truthy ( _) => match input {
159+ OutputShape :: Empty => EMPTY_ONLY ,
160+ OutputShape :: Rows => ROWS_ONLY ,
161+ OutputShape :: Detail => DETAIL_OR_EMPTY ,
162+ OutputShape :: Message => MESSAGE_OR_EMPTY ,
163+ OutputShape :: Values => VALUES_ONLY ,
164+ OutputShape :: Groups => GROUPS_ONLY ,
165+ OutputShape :: Lines => unreachable ! ( "validated input shape" ) ,
166+ } ,
167+ Self :: Head { .. } | Self :: Tail ( _) | Self :: SortLines { .. } => match input {
168+ OutputShape :: Empty => EMPTY_ONLY ,
169+ OutputShape :: Lines => LINES_ONLY ,
170+ OutputShape :: Rows => ROWS_ONLY ,
171+ OutputShape :: Values => VALUES_ONLY ,
172+ OutputShape :: Groups => GROUPS_ONLY ,
173+ OutputShape :: Detail | OutputShape :: Message => {
174+ unreachable ! ( "validated input shape" )
175+ }
176+ } ,
177+ Self :: Count => match input {
178+ OutputShape :: Groups => ROWS_ONLY ,
179+ _ => VALUES_ONLY ,
180+ } ,
181+ Self :: Columns ( _) => match input {
182+ OutputShape :: Empty => EMPTY_ONLY ,
183+ OutputShape :: Rows => ROWS_ONLY ,
184+ OutputShape :: Detail | OutputShape :: Message => DETAIL_ONLY ,
185+ OutputShape :: Groups => GROUPS_ONLY ,
186+ OutputShape :: Lines | OutputShape :: Values => {
187+ unreachable ! ( "validated input shape" )
188+ }
189+ } ,
190+ Self :: SortColumn { .. } | Self :: Unroll ( _) => match input {
191+ OutputShape :: Empty => EMPTY_ONLY ,
192+ OutputShape :: Rows => ROWS_ONLY ,
193+ OutputShape :: Values => VALUES_ONLY ,
194+ OutputShape :: Groups => GROUPS_ONLY ,
195+ OutputShape :: Lines | OutputShape :: Detail | OutputShape :: Message => {
196+ unreachable ! ( "validated input shape" )
197+ }
198+ } ,
199+ Self :: Group ( _) => GROUPS_ONLY ,
200+ Self :: Aggregate ( _) => GROUPS_ONLY ,
201+ Self :: CollapseGroups => ROWS_ONLY ,
202+ Self :: Jq ( _) => JQ_OUTPUT_SHAPES ,
203+ Self :: Value ( _) => VALUES_ONLY ,
204+ } ;
205+ Ok ( shapes)
206+ }
207+
208+ pub ( crate ) fn validate_input_shape ( & self , input : OutputShape ) -> Result < ( ) , PipelineError > {
209+ let accepted = self . accepted_input_shapes ( ) ;
210+ if accepted. contains ( & input) {
211+ return Ok ( ( ) ) ;
212+ }
213+
214+ let expected = accepted
215+ . iter ( )
216+ . map ( ToString :: to_string)
217+ . collect :: < Vec < _ > > ( )
218+ . join ( ", " ) ;
219+ Err ( PipelineError :: Pipe ( format ! (
220+ "Pipe stage '{}' does not accept {input} output; expected one of: {expected}" ,
221+ self . name( )
222+ ) ) )
223+ }
224+ }
225+
40226#[ derive( Debug , Clone , PartialEq , Eq ) ]
41227pub struct ProjectTerm {
42228 selector : Selector ,
@@ -204,6 +390,20 @@ pub enum OutputShape {
204390 Groups ,
205391}
206392
393+ impl Display for OutputShape {
394+ fn fmt ( & self , formatter : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
395+ formatter. write_str ( match self {
396+ Self :: Empty => "Empty" ,
397+ Self :: Lines => "Lines" ,
398+ Self :: Rows => "Rows" ,
399+ Self :: Detail => "Detail" ,
400+ Self :: Message => "Message" ,
401+ Self :: Values => "Values" ,
402+ Self :: Groups => "Groups" ,
403+ } )
404+ }
405+ }
406+
207407#[ derive( Debug , Clone , PartialEq , Serialize , Deserialize ) ]
208408pub struct OutputEnvelope {
209409 pub shape : OutputShape ,
0 commit comments