33
44use crate :: { AnyPtr , AsPointer , CFile , Ptr , Value } ;
55use std:: cell:: { RefCell , UnsafeCell } ;
6- use std:: os :: fd :: { AsFd , FromRawFd , IntoRawFd } ;
6+ use std:: io :: { self , Read , Write } ;
77use std:: rc:: Rc ;
88
9+ enum StreamHandle {
10+ File ( std:: fs:: File ) ,
11+ Standard ( i32 ) ,
12+ }
13+
14+ pub struct CppStream ( StreamHandle ) ;
15+
16+ impl From < std:: fs:: File > for CppStream {
17+ fn from ( file : std:: fs:: File ) -> Self {
18+ Self ( StreamHandle :: File ( file) )
19+ }
20+ }
21+
22+ impl CppStream {
23+ fn standard ( fd : i32 ) -> Self {
24+ Self ( StreamHandle :: Standard ( fd) )
25+ }
26+
27+ pub fn try_clone ( & self ) -> io:: Result < Self > {
28+ match & self . 0 {
29+ StreamHandle :: File ( file) => file. try_clone ( ) . map ( Self :: from) ,
30+ StreamHandle :: Standard ( fd) => Ok ( Self :: standard ( * fd) ) ,
31+ }
32+ }
33+ }
34+
35+ impl Read for & CppStream {
36+ fn read ( & mut self , buf : & mut [ u8 ] ) -> io:: Result < usize > {
37+ match & self . 0 {
38+ StreamHandle :: File ( file) => ( & * file) . read ( buf) ,
39+ StreamHandle :: Standard ( fd) => {
40+ // A standard descriptor may have been closed. Do not create an
41+ // owning File or a BorrowedFd, which requires an open descriptor.
42+ let n = unsafe { libc:: read ( * fd, buf. as_mut_ptr ( ) . cast ( ) , buf. len ( ) ) } ;
43+ if n < 0 {
44+ Err ( io:: Error :: last_os_error ( ) )
45+ } else {
46+ Ok ( n as usize )
47+ }
48+ }
49+ }
50+ }
51+ }
52+
53+ impl Read for CppStream {
54+ fn read ( & mut self , buf : & mut [ u8 ] ) -> io:: Result < usize > {
55+ ( & * self ) . read ( buf)
56+ }
57+ }
58+
59+ impl Write for CppStream {
60+ fn write ( & mut self , buf : & [ u8 ] ) -> io:: Result < usize > {
61+ match & mut self . 0 {
62+ StreamHandle :: File ( file) => file. write ( buf) ,
63+ StreamHandle :: Standard ( fd) => {
64+ // The slice is valid for the duration of this unbuffered write.
65+ let n = unsafe { libc:: write ( * fd, buf. as_ptr ( ) . cast ( ) , buf. len ( ) ) } ;
66+ if n < 0 {
67+ Err ( io:: Error :: last_os_error ( ) )
68+ } else {
69+ Ok ( n as usize )
70+ }
71+ }
72+ }
73+ }
74+
75+ fn flush ( & mut self ) -> io:: Result < ( ) > {
76+ match & mut self . 0 {
77+ StreamHandle :: File ( file) => file. flush ( ) ,
78+ StreamHandle :: Standard ( _) => Ok ( ( ) ) ,
79+ }
80+ }
81+ }
82+
83+ impl crate :: ByteRepr for CppStream { }
84+
985thread_local ! {
10- static SAFE_STDIN : Value <std:: fs:: File > = Rc :: new( RefCell :: new( std:: fs:: File :: from(
11- std:: io:: stdin( ) . as_fd( ) . try_clone_to_owned( ) . unwrap( ) ,
12- ) ) ) ;
13- static SAFE_STDOUT : Value <std:: fs:: File > = Rc :: new( RefCell :: new( std:: fs:: File :: from(
14- std:: io:: stdout( ) . as_fd( ) . try_clone_to_owned( ) . unwrap( ) ,
15- ) ) ) ;
16- static SAFE_STDERR : Value <std:: fs:: File > = Rc :: new( RefCell :: new( std:: fs:: File :: from(
17- std:: io:: stderr( ) . as_fd( ) . try_clone_to_owned( ) . unwrap( ) ,
18- ) ) ) ;
19- static UNSAFE_STDIN : UnsafeCell <std:: fs:: File > = unsafe {
20- UnsafeCell :: new(
21- std:: fs:: File :: from_raw_fd(
22- std:: io:: stdin( )
23- . as_fd( )
24- . try_clone_to_owned( )
25- . unwrap( )
26- . into_raw_fd( ) ,
27- ) )
28- } ;
29- static UNSAFE_STDOUT : UnsafeCell <std:: fs:: File > = unsafe {
30- UnsafeCell :: new(
31- std:: fs:: File :: from_raw_fd(
32- std:: io:: stdout( )
33- . as_fd( )
34- . try_clone_to_owned( )
35- . unwrap( )
36- . into_raw_fd( ) ,
37- ) )
38- } ;
39- static UNSAFE_STDERR : UnsafeCell <std:: fs:: File > = unsafe {
40- UnsafeCell :: new(
41- std:: fs:: File :: from_raw_fd(
42- std:: io:: stderr( )
43- . as_fd( )
44- . try_clone_to_owned( )
45- . unwrap( )
46- . into_raw_fd( ) ,
47- ) )
48- } ;
86+ static SAFE_STDIN : Value <CppStream > = Rc :: new( RefCell :: new( CppStream :: standard( 0 ) ) ) ;
87+ static SAFE_STDOUT : Value <CppStream > = Rc :: new( RefCell :: new( CppStream :: standard( 1 ) ) ) ;
88+ static SAFE_STDERR : Value <CppStream > = Rc :: new( RefCell :: new( CppStream :: standard( 2 ) ) ) ;
89+ static UNSAFE_STDIN : UnsafeCell <CppStream > = UnsafeCell :: new( CppStream :: standard( 0 ) ) ;
90+ static UNSAFE_STDOUT : UnsafeCell <CppStream > = UnsafeCell :: new( CppStream :: standard( 1 ) ) ;
91+ static UNSAFE_STDERR : UnsafeCell <CppStream > = UnsafeCell :: new( CppStream :: standard( 2 ) ) ;
4992}
5093
5194thread_local ! {
@@ -66,39 +109,39 @@ pub fn c_stderr() -> Ptr<CFile> {
66109 C_STDERR . with ( AsPointer :: as_pointer)
67110}
68111
69- pub fn cin ( ) -> Ptr < std :: fs :: File > {
112+ pub fn cin ( ) -> Ptr < CppStream > {
70113 SAFE_STDIN . with ( AsPointer :: as_pointer)
71114}
72115
73- pub fn cout ( ) -> Ptr < std :: fs :: File > {
116+ pub fn cout ( ) -> Ptr < CppStream > {
74117 SAFE_STDOUT . with ( AsPointer :: as_pointer)
75118}
76119
77- pub fn cerr ( ) -> Ptr < std :: fs :: File > {
120+ pub fn cerr ( ) -> Ptr < CppStream > {
78121 SAFE_STDERR . with ( AsPointer :: as_pointer)
79122}
80123
81124/// # Safety
82125///
83126/// The caller must ensure that the returned pointer is not used after the
84127/// thread finishes.
85- pub unsafe fn cin_unsafe ( ) -> * mut std :: fs :: File {
128+ pub unsafe fn cin_unsafe ( ) -> * mut CppStream {
86129 UNSAFE_STDIN . with ( UnsafeCell :: get)
87130}
88131
89132/// # Safety
90133///
91134/// The caller must ensure that the returned pointer is not used after the
92135/// thread finishes.
93- pub unsafe fn cout_unsafe ( ) -> * mut std :: fs :: File {
136+ pub unsafe fn cout_unsafe ( ) -> * mut CppStream {
94137 UNSAFE_STDOUT . with ( UnsafeCell :: get)
95138}
96139
97140/// # Safety
98141///
99142/// The caller must ensure that the returned pointer is not used after the
100143/// thread finishes.
101- pub unsafe fn cerr_unsafe ( ) -> * mut std :: fs :: File {
144+ pub unsafe fn cerr_unsafe ( ) -> * mut CppStream {
102145 UNSAFE_STDERR . with ( UnsafeCell :: get)
103146}
104147
@@ -189,3 +232,27 @@ pub unsafe fn fread_unsafe(
189232) -> usize {
190233 unsafe { libc:: fread ( a0, a1, a2, a3) }
191234}
235+
236+ #[ cfg( test) ]
237+ mod tests {
238+ use super :: * ;
239+
240+ #[ test]
241+ fn file_stream_io ( ) {
242+ let ( read, write) = nix:: unistd:: pipe ( ) . unwrap ( ) ;
243+ let mut input = CppStream :: from ( std:: fs:: File :: from ( read) ) ;
244+ let output = CppStream :: from ( std:: fs:: File :: from ( write) ) ;
245+ let mut copy = output. try_clone ( ) . unwrap ( ) ;
246+ drop ( output) ;
247+ copy. write_all ( & [ 0 , 127 , 255 ] ) . unwrap ( ) ;
248+ copy. flush ( ) . unwrap ( ) ;
249+ drop ( copy) ;
250+
251+ let mut first = [ 9 ] ;
252+ input. read_exact ( & mut first) . unwrap ( ) ;
253+ assert_eq ! ( first, [ 0 ] ) ;
254+ let mut rest = Vec :: new ( ) ;
255+ ( & input) . read_to_end ( & mut rest) . unwrap ( ) ;
256+ assert_eq ! ( rest, [ 127 , 255 ] ) ;
257+ }
258+ }
0 commit comments