@ -39,11 +39,29 @@ fn collect_input() -> Box<dyn Iterator<Item= impl Input + 'static> + 'static>
os ::unix ::ffi ::* ,
os ::unix ::ffi ::* ,
} ;
} ;
#[ derive(Debug) ]
//#[derive(Debug)]
enum MaybeUTF8
enum MaybeUTF8
{
{
UTF8 ( String ) ,
UTF8 ( String ) ,
Raw ( OsString ) ,
Raw ( OsString ) ,
Static ( & ' static [ u8 ] ) ,
}
impl std ::fmt ::Debug for MaybeUTF8
{
// Custom Debug impl to ensure output is identical when `output-quoted` is enabled.
#[ inline ]
fn fmt ( & self , f : & mut std ::fmt ::Formatter < ' _ > ) -> std ::fmt ::Result
{
let dbg : & dyn std ::fmt ::Debug = match self {
Self ::UTF8 ( string ) = > string ,
Self ::Raw ( raw ) = > raw ,
Self ::Static ( & [ ] ) = > return f . write_str ( "\"\"" ) ,
Self ::Static ( bytes ) = > return std ::fmt ::Debug ::fmt ( OsStr ::from_bytes ( bytes ) , f ) ,
} ;
std ::fmt ::Debug ::fmt ( dbg , f )
}
}
}
impl AsRef < [ u8 ] > for MaybeUTF8
impl AsRef < [ u8 ] > for MaybeUTF8
@ -54,6 +72,7 @@ fn collect_input() -> Box<dyn Iterator<Item= impl Input + 'static> + 'static>
match self {
match self {
Self ::UTF8 ( string ) = > string . as_bytes ( ) ,
Self ::UTF8 ( string ) = > string . as_bytes ( ) ,
Self ::Raw ( raw ) = > raw . as_bytes ( ) ,
Self ::Raw ( raw ) = > raw . as_bytes ( ) ,
Self ::Static ( bytes ) = > bytes ,
}
}
}
}
}
}
@ -76,16 +95,20 @@ fn collect_input() -> Box<dyn Iterator<Item= impl Input + 'static> + 'static>
}
}
}
}
#[ allow(dead_code) ]
impl MaybeUTF8
impl MaybeUTF8
{
{
#[ inline(always) ]
pub const fn from_static_bytes ( bytes : & ' static [ u8 ] ) -> Self
{
Self ::Static ( bytes )
}
#[ inline(always) ]
#[ inline(always) ]
pub fn from_raw_bytes ( bytes : & [ u8 ] ) -> Self
pub fn from_raw_bytes ( bytes : & [ u8 ] ) -> Self
{
{
Self ::Raw ( OsStr ::from_bytes ( bytes ) . to_os_string ( ) )
Self ::Raw ( OsStr ::from_bytes ( bytes ) . to_os_string ( ) )
}
}
#[ inline(always) ]
#[ inline(always) ]
#[ deprecated(note= " XXX: TODO: Only use this if the read_until() into vec does not add the ' \n ' into the vec as well. Otherwise, *always* use this. " ) ]
//#[deprecated(note=" XXX: TODO: Only use this if the read_until() into vec does not add the '\n' into the vec as well. Otherwise, *always* use this.")]
pub fn from_raw_vec ( vec : Vec < u8 > ) -> Self
pub fn from_raw_vec ( vec : Vec < u8 > ) -> Self
{
{
Self ::Raw ( OsString ::from_vec ( vec ) )
Self ::Raw ( OsString ::from_vec ( vec ) )
@ -116,10 +139,16 @@ fn collect_input() -> Box<dyn Iterator<Item= impl Input + 'static> + 'static>
{
{
Some ( match handle_fmt_err_or ( self . 0. read_until ( b'\n' , & mut self . 1 ) , | | 0 ) {
Some ( match handle_fmt_err_or ( self . 0. read_until ( b'\n' , & mut self . 1 ) , | | 0 ) {
0 = > return None ,
0 = > return None ,
1 if self . 1 [ 0 ] = = b'\n' = > MaybeUTF8 ::from_static_bytes ( & [ ] ) ,
read_sz = > {
read_sz = > {
let line = MaybeUTF8 ::from_raw_bytes ( & self . 1 [ .. ] ) ; //TODO: XXX: If self.1 here does not have the '\n' added into it by read_until(); use from_raw_vec(self.1.clone()) instead; it'll be more efficient.
let line = if self . 1 [ read_sz - 1 ] = = b'\n' {
MaybeUTF8 ::from_raw_bytes ( & self . 1 [ .. ( read_sz - 1 ) ] )
} else {
MaybeUTF8 ::from_raw_vec ( self . 1. clone ( ) )
} ;
debug_assert_ne! ( line . as_ref ( ) . iter ( ) . last ( ) . copied ( ) , Some ( b'\n' ) , "Deliminator still in output" ) ;
self . 1. clear ( ) ;
self . 1. clear ( ) ;
//TODO: todo!("Do we need read_sz ({read_sz}) at all here? Will the `\n` be inside the read string?");
line
line
} ,
} ,
} )
} )
@ -141,20 +170,26 @@ fn collect_input() -> Box<dyn Iterator<Item= impl Input + 'static> + 'static>
}
}
}
}
#[ allow(dead_code) ]
#[ cfg_attr(feature= " ignore-output-errors " , inline) ]
#[ cfg_attr(feature= " ignore-output-errors " , inline) ]
fn handle_fmt_err_or < F , T > ( res : std ::io ::Result < T > , or : F ) -> T
fn handle_fmt_err_or < F , T > ( res : std ::io ::Result < T > , or : F ) -> T
where F : FnOnce ( ) -> T
where F : FnOnce ( ) -> T
{
{
#[ cfg(not(feature= " ignore-output-errors " )) ]
#[ cfg(not(feature= " ignore-output-errors " )) ] {
if let Err ( e ) = res {
match res {
eprintln! ( "[!] failed to write line: {e}" ) ;
Ok ( v ) = > return v ,
or ( )
Err ( e ) = > eprintln! ( "[!] failed to write line: {e}" ) ,
}
return or ( ) ;
}
}
#[ cfg(feature= " ignore-output-errors " ) ]
#[ cfg(feature= " ignore-output-errors " ) ]
res . unwrap_or_else ( | _ | or ( ) )
res . unwrap_or_else ( | _ | or ( ) )
}
}
#[ cfg_attr(feature= " ignore-output-errors " , inline(always)) ]
#[ allow(dead_code) ]
#[ cfg_attr(feature= " ignore-output-errors " , inline(always)) ]
fn handle_fmt_err < T > ( res : std ::io ::Result < T > )
fn handle_fmt_err < T > ( res : std ::io ::Result < T > )
{
{
#[ cfg(not(feature= " ignore-output-errors " )) ]
#[ cfg(not(feature= " ignore-output-errors " )) ]