11
11
use prelude:: * ;
12
12
use ptr:: null;
13
13
use libc:: c_void;
14
- use rt:: uv:: { Request , NativeHandle , Loop , FsCallback } ;
14
+ use rt:: uv:: { Request , NativeHandle , Loop , FsCallback ,
15
+ status_to_maybe_uv_error_with_loop} ;
15
16
use rt:: uv:: uvll;
16
17
use rt:: uv:: uvll:: * ;
18
+ use path:: Path ;
19
+ use cast:: transmute;
20
+ use libc:: { c_int} ;
17
21
18
22
pub struct FsRequest ( * uvll:: uv_fs_t ) ;
19
23
impl Request for FsRequest ;
20
24
25
+ #[ allow( non_camel_case_types) ]
26
+ pub enum UvFileFlag {
27
+ O_RDONLY ,
28
+ O_WRONLY ,
29
+ O_RDWR ,
30
+ O_CREAT ,
31
+ O_TRUNC
32
+ }
33
+ pub fn map_flag ( v : UvFileFlag ) -> int {
34
+ unsafe {
35
+ match v {
36
+ O_RDONLY => uvll:: get_O_RDONLY ( ) as int ,
37
+ O_WRONLY => uvll:: get_O_WRONLY ( ) as int ,
38
+ O_RDWR => uvll:: get_O_RDWR ( ) as int ,
39
+ O_CREAT => uvll:: get_O_CREAT ( ) as int ,
40
+ O_TRUNC => uvll:: get_O_TRUNC ( ) as int
41
+ }
42
+ }
43
+ }
44
+
45
+ pub struct RequestData {
46
+ complete_cb : Option < FsCallback >
47
+ }
48
+
21
49
impl FsRequest {
22
- fn new ( ) -> FsRequest {
50
+ pub fn new ( cb : Option < FsCallback > ) -> FsRequest {
23
51
let fs_req = unsafe { malloc_req ( UV_FS ) } ;
24
52
assert ! ( fs_req. is_not_null( ) ) ;
25
- let fs_req = fs_req as * uvll:: uv_write_t ;
26
- unsafe { uvll:: set_data_for_req ( fs_req, null :: < ( ) > ( ) ) ; }
27
- NativeHandle :: from_native_handle ( fs_req)
53
+ let fs_req: FsRequest = NativeHandle :: from_native_handle ( fs_req) ;
54
+ fs_req. install_req_data ( cb) ;
55
+ fs_req
56
+ }
57
+
58
+ pub fn install_req_data ( & self , cb : Option < FsCallback > ) {
59
+ let fs_req = ( self . native_handle ( ) ) as * uvll:: uv_write_t ;
60
+ let data = ~RequestData {
61
+ complete_cb : cb
62
+ } ;
63
+ unsafe {
64
+ let data = transmute :: < ~RequestData , * c_void > ( data) ;
65
+ uvll:: set_data_for_req ( fs_req, data) ;
66
+ }
28
67
}
29
68
30
- fn delete ( self ) {
31
- unsafe { free_req ( self . native_handle ( ) as * c_void ) }
69
+ fn get_req_data < ' r > ( & ' r mut self ) -> & ' r mut RequestData {
70
+ unsafe {
71
+ let data = uvll:: get_data_for_req ( ( self . native_handle ( ) ) ) ;
72
+ let data = transmute :: < & * c_void , & mut ~RequestData > ( & data) ;
73
+ return & mut * * data;
74
+ }
32
75
}
33
76
34
- fn open ( & mut self , _loop_ : & Loop , _cb : FsCallback ) {
77
+ pub fn get_result ( & mut self ) -> c_int {
78
+ unsafe {
79
+ uvll:: get_result_from_fs_req ( self . native_handle ( ) )
80
+ }
35
81
}
36
82
37
- fn close ( & mut self , _loop_ : & Loop , _cb : FsCallback ) {
83
+ pub fn get_loop ( & self ) -> Loop {
84
+ unsafe { Loop { handle : uvll:: get_loop_from_fs_req ( self . native_handle ( ) ) } }
85
+ }
86
+
87
+ fn cleanup_and_delete ( self ) {
88
+ unsafe {
89
+ uvll:: fs_req_cleanup ( self . native_handle ( ) ) ;
90
+ let data = uvll:: get_data_for_uv_handle ( self . native_handle ( ) ) ;
91
+ let _data = transmute :: < * c_void , ~RequestData > ( data) ;
92
+ uvll:: set_data_for_uv_handle ( self . native_handle ( ) , null :: < ( ) > ( ) ) ;
93
+ free_req ( self . native_handle ( ) as * c_void )
94
+ }
38
95
}
39
96
}
40
97
@@ -46,3 +103,97 @@ impl NativeHandle<*uvll::uv_fs_t> for FsRequest {
46
103
match self { & FsRequest ( ptr) => ptr }
47
104
}
48
105
}
106
+
107
+ pub struct FileDescriptor ( c_int ) ;
108
+ impl FileDescriptor {
109
+ fn new ( fd : c_int ) -> FileDescriptor {
110
+ FileDescriptor ( fd)
111
+ }
112
+
113
+ pub fn from_open_req ( req : & mut FsRequest ) -> FileDescriptor {
114
+ FileDescriptor :: new ( req. get_result ( ) )
115
+ }
116
+
117
+ pub fn open ( loop_ : Loop , path : Path , flags : int , mode : int ,
118
+ cb : FsCallback ) -> int {
119
+ let req = FsRequest :: new ( Some ( cb) ) ;
120
+ path. to_str ( ) . to_c_str ( ) . with_ref ( |p| unsafe {
121
+ uvll:: fs_open ( loop_. native_handle ( ) ,
122
+ req. native_handle ( ) , p, flags, mode, complete_cb) as int
123
+ } )
124
+
125
+ }
126
+
127
+ fn close ( self , loop_ : Loop , cb : FsCallback ) -> int {
128
+ let req = FsRequest :: new ( Some ( cb) ) ;
129
+ unsafe {
130
+ uvll:: fs_close ( loop_. native_handle ( ) , req. native_handle ( ) ,
131
+ self . native_handle ( ) , complete_cb) as int
132
+ }
133
+ }
134
+ }
135
+ extern fn complete_cb ( req : * uv_fs_t ) {
136
+ let mut req: FsRequest = NativeHandle :: from_native_handle ( req) ;
137
+ let loop_ = req. get_loop ( ) ;
138
+ // pull the user cb out of the req data
139
+ let cb = {
140
+ let data = req. get_req_data ( ) ;
141
+ assert ! ( data. complete_cb. is_some( ) ) ;
142
+ // option dance, option dance. oooooh yeah.
143
+ data. complete_cb . take_unwrap ( )
144
+ } ;
145
+ // in uv_fs_open calls, the result will be the fd in the
146
+ // case of success, otherwise it's -1 indicating an error
147
+ let result = req. get_result ( ) ;
148
+ let status = status_to_maybe_uv_error_with_loop (
149
+ loop_. native_handle ( ) , result) ;
150
+ // we have a req and status, call the user cb..
151
+ // only giving the user a ref to the FsRequest, as we
152
+ // have to clean it up, afterwards (and they aren't really
153
+ // reusable, anyways
154
+ cb ( & mut req, status) ;
155
+ // clean up the req (and its data!) after calling the user cb
156
+ req. cleanup_and_delete ( ) ;
157
+ }
158
+
159
+ impl NativeHandle < c_int > for FileDescriptor {
160
+ fn from_native_handle ( handle : c_int ) -> FileDescriptor {
161
+ FileDescriptor ( handle)
162
+ }
163
+ fn native_handle ( & self ) -> c_int {
164
+ match self { & FileDescriptor ( ptr) => ptr }
165
+ }
166
+ }
167
+
168
+ mod test {
169
+ use super :: * ;
170
+ //use rt::test::*;
171
+ use unstable:: run_in_bare_thread;
172
+ use path:: Path ;
173
+ use rt:: uv:: Loop ;
174
+
175
+ // this is equiv to touch, i guess?
176
+ fn file_test_touch_impl ( ) {
177
+ debug ! ( "hello?" )
178
+ do run_in_bare_thread {
179
+ debug!( "In bare thread" )
180
+ let loop_ = Loop :: new ( ) ;
181
+ let flags = map_flag ( O_RDWR ) |
182
+ map_flag ( O_CREAT ) | map_flag ( O_TRUNC ) ;
183
+ do FileDescriptor :: open ( loop_, Path ( "./foo.txt" ) , flags, 0644 )
184
+ |req, uverr| {
185
+ let loop_ = req. get_loop ( ) ;
186
+ assert ! ( uverr. is_none( ) ) ;
187
+ let fd = FileDescriptor :: from_open_req ( req) ;
188
+ do fd. close ( loop_) |_, uverr| {
189
+ assert ! ( uverr. is_none( ) ) ;
190
+ } ;
191
+ } ;
192
+ }
193
+ }
194
+
195
+ #[ test]
196
+ fn file_test_touch ( ) {
197
+ file_test_touch_impl ( ) ;
198
+ }
199
+ }
0 commit comments