@@ -205,6 +205,34 @@ fn read_and_discard<R: Read>(reader: &mut R, n: u64, buf_size: usize) -> io::Res
205205 Ok ( total)
206206}
207207
208+ #[ cfg( unix) ]
209+ struct StdinRaw ( core:: mem:: ManuallyDrop < File > ) ;
210+
211+ #[ cfg( unix) ]
212+ impl StdinRaw {
213+ fn new ( ) -> Self {
214+ let fd = io:: stdin ( ) . as_raw_fd ( ) ;
215+ let f = unsafe { File :: from_raw_fd ( fd) } ;
216+ Self ( core:: mem:: ManuallyDrop :: new ( f) )
217+ }
218+ }
219+
220+ #[ cfg( unix) ]
221+ impl core:: ops:: Deref for StdinRaw {
222+ type Target = File ;
223+
224+ fn deref ( & self ) -> & Self :: Target {
225+ & self . 0
226+ }
227+ }
228+
229+ #[ cfg( unix) ]
230+ impl core:: ops:: DerefMut for StdinRaw {
231+ fn deref_mut ( & mut self ) -> & mut Self :: Target {
232+ & mut self . 0
233+ }
234+ }
235+
208236/// Data sources.
209237///
210238/// Use [`Source::stdin_as_file`] if available to enable more
@@ -219,7 +247,7 @@ enum Source {
219247
220248 /// Input from stdin, opened from its file descriptor.
221249 #[ cfg( unix) ]
222- StdinFile ( File ) ,
250+ StdinRaw ( StdinRaw ) ,
223251
224252 /// Input from a named pipe, also known as a FIFO.
225253 #[ cfg( unix) ]
@@ -229,16 +257,14 @@ enum Source {
229257impl Source {
230258 /// Create a source from stdin using its raw file descriptor.
231259 ///
232- /// This returns an instance of the `Source::StdinFile ` variant,
260+ /// This returns an instance of the `Source::StdinRaw ` variant,
233261 /// using the raw file descriptor of [`io::Stdin`] to create
234262 /// the [`File`] parameter. You can use this instead of
235263 /// `Source::Stdin` to allow reading from stdin without consuming
236264 /// the entire contents of stdin when this process terminates.
237265 #[ cfg( unix) ]
238- fn stdin_as_file ( ) -> Self {
239- let fd = io:: stdin ( ) . as_raw_fd ( ) ;
240- let f = unsafe { File :: from_raw_fd ( fd) } ;
241- Self :: StdinFile ( f)
266+ fn stdin_raw ( ) -> Self {
267+ Self :: StdinRaw ( StdinRaw :: new ( ) )
242268 }
243269
244270 fn skip ( & mut self , n : u64 , ibs : usize ) -> io:: Result < u64 > {
@@ -255,7 +281,7 @@ impl Source {
255281 Ok ( m)
256282 }
257283 #[ cfg( unix) ]
258- Self :: StdinFile ( f) => {
284+ Self :: StdinRaw ( f) => {
259285 if let Ok ( Some ( len) ) = try_get_len_of_block_device ( f)
260286 && len < n
261287 {
@@ -284,7 +310,7 @@ impl Source {
284310 // ESPIPE means the file descriptor is not seekable (e.g., a pipe),
285311 // so fall back to reading and discarding bytes using ibs-sized buffer
286312 Some ( Err ( e) ) if e. raw_os_error ( ) == Some ( libc:: ESPIPE ) => {
287- let m = read_and_discard ( f, n, ibs) ?;
313+ let m = read_and_discard :: < File > ( f, n, ibs) ?;
288314 if m < n {
289315 show_error ! (
290316 "{}" ,
@@ -335,7 +361,7 @@ impl Read for Source {
335361 Self :: Stdin ( stdin) => stdin. read ( buf) ,
336362 Self :: File ( f) => f. read ( buf) ,
337363 #[ cfg( unix) ]
338- Self :: StdinFile ( f) => f. read ( buf) ,
364+ Self :: StdinRaw ( f) => f. read ( buf) ,
339365 #[ cfg( unix) ]
340366 Self :: Fifo ( f) => f. read ( buf) ,
341367 }
@@ -379,9 +405,9 @@ impl<'a> Input<'a> {
379405 }
380406 } ;
381407 #[ cfg( unix) ]
382- let mut src = Source :: stdin_as_file ( ) ;
408+ let mut src = Source :: stdin_raw ( ) ;
383409 #[ cfg( unix) ]
384- if let Source :: StdinFile ( f) = & src
410+ if let Source :: StdinRaw ( f) = & src
385411 && settings. iflags . directory
386412 && !f. metadata ( ) ?. is_dir ( )
387413 {
0 commit comments