@@ -8,96 +8,6 @@ use std::sync::mpsc::{Receiver, channel};
88use std:: thread;
99use std:: { fmt, time} ;
1010
11- #[ derive( Debug ) ]
12- enum PipeError {
13- IO ( io:: Error ) ,
14- }
15-
16- #[ derive( Debug ) ]
17- #[ allow( clippy:: upper_case_acronyms) ]
18- enum PipedChar {
19- Char ( u8 ) ,
20- EOF ,
21- }
22-
23- pub enum ReadUntil {
24- String ( String ) ,
25- Regex ( Regex ) ,
26- EOF ,
27- NBytes ( usize ) ,
28- Any ( Vec < ReadUntil > ) ,
29- }
30-
31- impl fmt:: Display for ReadUntil {
32- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
33- let printable = match self {
34- ReadUntil :: String ( s) if s == "\n " => "\\ n (newline)" . to_owned ( ) ,
35- ReadUntil :: String ( s) if s == "\r " => "\\ r (carriage return)" . to_owned ( ) ,
36- ReadUntil :: String ( s) => format ! ( "\" {s}\" " ) ,
37- ReadUntil :: Regex ( r) => format ! ( "Regex: \" {r}\" " ) ,
38- ReadUntil :: EOF => "EOF (End of File)" . to_owned ( ) ,
39- ReadUntil :: NBytes ( n) => format ! ( "reading {n} bytes" ) ,
40- ReadUntil :: Any ( v) => {
41- let mut res = Vec :: new ( ) ;
42- for r in v {
43- res. push ( r. to_string ( ) ) ;
44- }
45- res. join ( ", " )
46- }
47- } ;
48- write ! ( f, "{printable}" )
49- }
50- }
51-
52- /// find first occurrence of needle within buffer
53- ///
54- /// # Arguments:
55- ///
56- /// - buffer: the currently read buffer from a process which will still grow in the future
57- /// - eof: if the process already sent an EOF or a HUP
58- ///
59- /// # Return
60- ///
61- /// Tuple with match positions:
62- /// 1. position before match (0 in case of EOF and Nbytes)
63- /// 2. position after match
64- pub fn find ( needle : & ReadUntil , buffer : & str , eof : bool ) -> Option < ( usize , usize ) > {
65- match needle {
66- ReadUntil :: String ( s) => buffer. find ( s) . map ( |pos| ( pos, pos + s. len ( ) ) ) ,
67- ReadUntil :: Regex ( pattern) => pattern. find ( buffer) . map ( |mat| ( mat. start ( ) , mat. end ( ) ) ) ,
68- ReadUntil :: EOF => {
69- if eof {
70- Some ( ( 0 , buffer. len ( ) ) )
71- } else {
72- None
73- }
74- }
75- ReadUntil :: NBytes ( n) => {
76- if * n <= buffer. len ( ) {
77- Some ( ( 0 , * n) )
78- } else if eof && !buffer. is_empty ( ) {
79- // reached almost end of buffer, return string, even though it will be
80- // smaller than the wished n bytes
81- Some ( ( 0 , buffer. len ( ) ) )
82- } else {
83- None
84- }
85- }
86- ReadUntil :: Any ( anys) => anys
87- . iter ( )
88- // Filter matching needles
89- . filter_map ( |any| find ( any, buffer, eof) )
90- // Return the left-most match
91- . min_by ( |( start1, end1) , ( start2, end2) | {
92- if start1 == start2 {
93- end1. cmp ( end2)
94- } else {
95- start1. cmp ( start2)
96- }
97- } ) ,
98- }
99- }
100-
10111/// Options for `NBReader`
10212///
10313/// - timeout:
@@ -296,6 +206,96 @@ impl NBReader {
296206 }
297207}
298208
209+ pub enum ReadUntil {
210+ String ( String ) ,
211+ Regex ( Regex ) ,
212+ EOF ,
213+ NBytes ( usize ) ,
214+ Any ( Vec < ReadUntil > ) ,
215+ }
216+
217+ impl fmt:: Display for ReadUntil {
218+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
219+ let printable = match self {
220+ ReadUntil :: String ( s) if s == "\n " => "\\ n (newline)" . to_owned ( ) ,
221+ ReadUntil :: String ( s) if s == "\r " => "\\ r (carriage return)" . to_owned ( ) ,
222+ ReadUntil :: String ( s) => format ! ( "\" {s}\" " ) ,
223+ ReadUntil :: Regex ( r) => format ! ( "Regex: \" {r}\" " ) ,
224+ ReadUntil :: EOF => "EOF (End of File)" . to_owned ( ) ,
225+ ReadUntil :: NBytes ( n) => format ! ( "reading {n} bytes" ) ,
226+ ReadUntil :: Any ( v) => {
227+ let mut res = Vec :: new ( ) ;
228+ for r in v {
229+ res. push ( r. to_string ( ) ) ;
230+ }
231+ res. join ( ", " )
232+ }
233+ } ;
234+ write ! ( f, "{printable}" )
235+ }
236+ }
237+
238+ /// find first occurrence of needle within buffer
239+ ///
240+ /// # Arguments:
241+ ///
242+ /// - buffer: the currently read buffer from a process which will still grow in the future
243+ /// - eof: if the process already sent an EOF or a HUP
244+ ///
245+ /// # Return
246+ ///
247+ /// Tuple with match positions:
248+ /// 1. position before match (0 in case of EOF and Nbytes)
249+ /// 2. position after match
250+ pub fn find ( needle : & ReadUntil , buffer : & str , eof : bool ) -> Option < ( usize , usize ) > {
251+ match needle {
252+ ReadUntil :: String ( s) => buffer. find ( s) . map ( |pos| ( pos, pos + s. len ( ) ) ) ,
253+ ReadUntil :: Regex ( pattern) => pattern. find ( buffer) . map ( |mat| ( mat. start ( ) , mat. end ( ) ) ) ,
254+ ReadUntil :: EOF => {
255+ if eof {
256+ Some ( ( 0 , buffer. len ( ) ) )
257+ } else {
258+ None
259+ }
260+ }
261+ ReadUntil :: NBytes ( n) => {
262+ if * n <= buffer. len ( ) {
263+ Some ( ( 0 , * n) )
264+ } else if eof && !buffer. is_empty ( ) {
265+ // reached almost end of buffer, return string, even though it will be
266+ // smaller than the wished n bytes
267+ Some ( ( 0 , buffer. len ( ) ) )
268+ } else {
269+ None
270+ }
271+ }
272+ ReadUntil :: Any ( anys) => anys
273+ . iter ( )
274+ // Filter matching needles
275+ . filter_map ( |any| find ( any, buffer, eof) )
276+ // Return the left-most match
277+ . min_by ( |( start1, end1) , ( start2, end2) | {
278+ if start1 == start2 {
279+ end1. cmp ( end2)
280+ } else {
281+ start1. cmp ( start2)
282+ }
283+ } ) ,
284+ }
285+ }
286+
287+ #[ derive( Debug ) ]
288+ enum PipeError {
289+ IO ( io:: Error ) ,
290+ }
291+
292+ #[ derive( Debug ) ]
293+ #[ allow( clippy:: upper_case_acronyms) ]
294+ enum PipedChar {
295+ Char ( u8 ) ,
296+ EOF ,
297+ }
298+
299299#[ cfg( test) ]
300300mod tests {
301301 use super :: * ;
0 commit comments