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+ // The stream object is separate from its I/O handle so formatting and error
15+ // state can live here. References and iterators must refer to this same object,
16+ // not clone its handle into another stream.
17+ pub struct CppStream {
18+ handle : StreamHandle ,
19+ }
20+
21+ impl From < std:: fs:: File > for CppStream {
22+ fn from ( file : std:: fs:: File ) -> Self {
23+ Self {
24+ handle : StreamHandle :: File ( file) ,
25+ }
26+ }
27+ }
28+
29+ impl CppStream {
30+ fn standard ( fd : i32 ) -> Self {
31+ Self {
32+ handle : StreamHandle :: Standard ( fd) ,
33+ }
34+ }
35+ }
36+
37+ impl Read for CppStream {
38+ fn read ( & mut self , buf : & mut [ u8 ] ) -> io:: Result < usize > {
39+ match & mut self . handle {
40+ StreamHandle :: File ( file) => file. read ( buf) ,
41+ StreamHandle :: Standard ( fd) => {
42+ // A standard descriptor may have been closed. Do not create an
43+ // owning File or a BorrowedFd, which requires an open descriptor.
44+ let n = unsafe { libc:: read ( * fd, buf. as_mut_ptr ( ) . cast ( ) , buf. len ( ) ) } ;
45+ if n < 0 {
46+ Err ( io:: Error :: last_os_error ( ) )
47+ } else {
48+ Ok ( n as usize )
49+ }
50+ }
51+ }
52+ }
53+ }
54+
55+ impl Write for CppStream {
56+ fn write ( & mut self , buf : & [ u8 ] ) -> io:: Result < usize > {
57+ match & mut self . handle {
58+ StreamHandle :: File ( file) => file. write ( buf) ,
59+ StreamHandle :: Standard ( fd) => {
60+ // The slice is valid for the duration of this unbuffered write.
61+ let n = unsafe { libc:: write ( * fd, buf. as_ptr ( ) . cast ( ) , buf. len ( ) ) } ;
62+ if n < 0 {
63+ Err ( io:: Error :: last_os_error ( ) )
64+ } else {
65+ Ok ( n as usize )
66+ }
67+ }
68+ }
69+ }
70+
71+ fn flush ( & mut self ) -> io:: Result < ( ) > {
72+ match & mut self . handle {
73+ StreamHandle :: File ( file) => file. flush ( ) ,
74+ StreamHandle :: Standard ( _) => Ok ( ( ) ) ,
75+ }
76+ }
77+ }
78+
79+ impl crate :: ByteRepr for CppStream { }
80+
981thread_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- } ;
82+ static SAFE_STDIN : Value <CppStream > = Rc :: new( RefCell :: new( CppStream :: standard( 0 ) ) ) ;
83+ static SAFE_STDOUT : Value <CppStream > = Rc :: new( RefCell :: new( CppStream :: standard( 1 ) ) ) ;
84+ static SAFE_STDERR : Value <CppStream > = Rc :: new( RefCell :: new( CppStream :: standard( 2 ) ) ) ;
85+ static UNSAFE_STDIN : UnsafeCell <CppStream > = UnsafeCell :: new( CppStream :: standard( 0 ) ) ;
86+ static UNSAFE_STDOUT : UnsafeCell <CppStream > = UnsafeCell :: new( CppStream :: standard( 1 ) ) ;
87+ static UNSAFE_STDERR : UnsafeCell <CppStream > = UnsafeCell :: new( CppStream :: standard( 2 ) ) ;
4988}
5089
5190thread_local ! {
@@ -66,39 +105,39 @@ pub fn c_stderr() -> Ptr<CFile> {
66105 C_STDERR . with ( AsPointer :: as_pointer)
67106}
68107
69- pub fn cin ( ) -> Ptr < std :: fs :: File > {
108+ pub fn cin ( ) -> Ptr < CppStream > {
70109 SAFE_STDIN . with ( AsPointer :: as_pointer)
71110}
72111
73- pub fn cout ( ) -> Ptr < std :: fs :: File > {
112+ pub fn cout ( ) -> Ptr < CppStream > {
74113 SAFE_STDOUT . with ( AsPointer :: as_pointer)
75114}
76115
77- pub fn cerr ( ) -> Ptr < std :: fs :: File > {
116+ pub fn cerr ( ) -> Ptr < CppStream > {
78117 SAFE_STDERR . with ( AsPointer :: as_pointer)
79118}
80119
81120/// # Safety
82121///
83122/// The caller must ensure that the returned pointer is not used after the
84123/// thread finishes.
85- pub unsafe fn cin_unsafe ( ) -> * mut std :: fs :: File {
124+ pub unsafe fn cin_unsafe ( ) -> * mut CppStream {
86125 UNSAFE_STDIN . with ( UnsafeCell :: get)
87126}
88127
89128/// # Safety
90129///
91130/// The caller must ensure that the returned pointer is not used after the
92131/// thread finishes.
93- pub unsafe fn cout_unsafe ( ) -> * mut std :: fs :: File {
132+ pub unsafe fn cout_unsafe ( ) -> * mut CppStream {
94133 UNSAFE_STDOUT . with ( UnsafeCell :: get)
95134}
96135
97136/// # Safety
98137///
99138/// The caller must ensure that the returned pointer is not used after the
100139/// thread finishes.
101- pub unsafe fn cerr_unsafe ( ) -> * mut std :: fs :: File {
140+ pub unsafe fn cerr_unsafe ( ) -> * mut CppStream {
102141 UNSAFE_STDERR . with ( UnsafeCell :: get)
103142}
104143
@@ -189,3 +228,27 @@ pub unsafe fn fread_unsafe(
189228) -> usize {
190229 unsafe { libc:: fread ( a0, a1, a2, a3) }
191230}
231+
232+ #[ cfg( test) ]
233+ mod tests {
234+ use super :: * ;
235+
236+ #[ test]
237+ fn file_stream_io ( ) {
238+ let ( read, write) = nix:: unistd:: pipe ( ) . unwrap ( ) ;
239+ let mut input = CppStream :: from ( std:: fs:: File :: from ( read) ) ;
240+ let output = Rc :: new ( RefCell :: new ( CppStream :: from ( std:: fs:: File :: from ( write) ) ) ) ;
241+ let stream = output. as_pointer ( ) ;
242+ let copy = stream. clone ( ) ;
243+ stream. write_all ( & [ 0 , 127 , 255 ] ) . unwrap ( ) ;
244+ copy. with_mut ( |s| s. flush ( ) ) . unwrap ( ) ;
245+ drop ( output) ;
246+
247+ let mut first = [ 9 ] ;
248+ input. read_exact ( & mut first) . unwrap ( ) ;
249+ assert_eq ! ( first, [ 0 ] ) ;
250+ let mut rest = Vec :: new ( ) ;
251+ input. read_to_end ( & mut rest) . unwrap ( ) ;
252+ assert_eq ! ( rest, [ 127 , 255 ] ) ;
253+ }
254+ }
0 commit comments