11use std:: {
2- future :: Future ,
2+ io ,
33 path:: { Path , PathBuf } ,
4- pin:: Pin ,
5- sync:: { Arc , Mutex } ,
6- task:: { Context , Poll , Waker } ,
74} ;
85
9- #[ derive( Default ) ]
10- struct ReaderState {
11- res : Option < std:: io:: Result < Vec < u8 > > > ,
12- waker : Option < Waker > ,
13- }
14-
15- struct Reader {
16- state : Arc < Mutex < ReaderState > > ,
17- }
18-
19- impl Reader {
20- fn new ( path : & Path ) -> Self {
21- let state: Arc < Mutex < ReaderState > > = Arc :: new ( Mutex :: new ( Default :: default ( ) ) ) ;
22-
23- {
24- let path = path. to_owned ( ) ;
25- let state = state. clone ( ) ;
26- std:: thread:: Builder :: new ( )
27- . name ( "rfd_file_read" . into ( ) )
28- . spawn ( move || {
29- let res = std:: fs:: read ( path) ;
30-
31- let mut state = state. lock ( ) . unwrap ( ) ;
32- state. res . replace ( res) ;
33-
34- if let Some ( waker) = state. waker . take ( ) {
35- waker. wake ( ) ;
36- }
37- } )
38- . unwrap ( ) ;
39- }
40-
41- Self { state }
42- }
43- }
44-
45- impl Future for Reader {
46- type Output = Vec < u8 > ;
47-
48- fn poll ( self : Pin < & mut Self > , ctx : & mut Context < ' _ > ) -> Poll < Self :: Output > {
49- let mut state = self . state . lock ( ) . unwrap ( ) ;
50- if let Some ( res) = state. res . take ( ) {
51- Poll :: Ready ( res. unwrap ( ) )
52- } else {
53- state. waker . replace ( ctx. waker ( ) . clone ( ) ) ;
54- Poll :: Pending
55- }
56- }
57- }
58-
59- struct WriterState {
60- waker : Option < Waker > ,
61- res : Option < std:: io:: Result < ( ) > > ,
62- }
63-
64- struct Writer {
65- state : Arc < Mutex < WriterState > > ,
66- }
67-
68- impl Writer {
69- fn new ( path : & Path , bytes : & [ u8 ] ) -> Self {
70- let state = Arc :: new ( Mutex :: new ( WriterState {
71- waker : None ,
72- res : None ,
73- } ) ) ;
74-
75- {
76- let path = path. to_owned ( ) ;
77- let bytes = bytes. to_owned ( ) ;
78- let state = state. clone ( ) ;
79- std:: thread:: Builder :: new ( )
80- . name ( "rfd_file_write" . into ( ) )
81- . spawn ( move || {
82- let res = std:: fs:: write ( path, bytes) ;
83-
84- let mut state = state. lock ( ) . unwrap ( ) ;
85- state. res . replace ( res) ;
86-
87- if let Some ( waker) = state. waker . take ( ) {
88- waker. wake ( ) ;
89- }
90- } )
91- . unwrap ( ) ;
92- }
93-
94- Self { state }
95- }
96- }
97-
98- impl Future for Writer {
99- type Output = std:: io:: Result < ( ) > ;
100-
101- fn poll ( self : Pin < & mut Self > , ctx : & mut Context < ' _ > ) -> Poll < Self :: Output > {
102- let mut state = self . state . lock ( ) . unwrap ( ) ;
103- if let Some ( res) = state. res . take ( ) {
104- Poll :: Ready ( res)
105- } else {
106- state. waker . replace ( ctx. waker ( ) . clone ( ) ) ;
107- Poll :: Pending
108- }
109- }
110- }
6+ use super :: super :: oneshot;
1117
1128/// FileHandle is a way of abstracting over a file returned by a dialog
1139#[ derive( Clone ) ]
@@ -143,7 +39,22 @@ impl FileHandle {
14339 ///
14440 /// `This fn exists solely to keep native api in pair with async only web api.`
14541 pub async fn read ( & self ) -> Vec < u8 > {
146- Reader :: new ( & self . 0 ) . await
42+ let ( tx, rx) = oneshot:: channel ( ) ;
43+ let path = self . 0 . clone ( ) ;
44+
45+ std:: thread:: Builder :: new ( )
46+ . name ( "rfd_file_read" . into ( ) )
47+ . spawn ( move || {
48+ tx. send ( std:: fs:: read ( path) ) . unwrap ( ) ;
49+ } )
50+ . unwrap ( ) ;
51+
52+ match rx. await {
53+ Ok ( res) => res,
54+ Err ( _) => Err ( io:: Error :: other ( "Read tread panicked" ) ) ,
55+ }
56+ // TODO: Move to io::Result
57+ . unwrap ( )
14758 }
14859
14960 /// Writes a file asynchronously.
@@ -152,7 +63,22 @@ impl FileHandle {
15263 ///
15364 /// `This fn exists solely to keep native api in pair with async only web api.`
15465 pub async fn write ( & self , data : & [ u8 ] ) -> std:: io:: Result < ( ) > {
155- Writer :: new ( & self . 0 , data) . await
66+ let ( tx, rx) = oneshot:: channel ( ) ;
67+
68+ let path = self . 0 . clone ( ) ;
69+ let bytes = data. to_owned ( ) ;
70+
71+ std:: thread:: Builder :: new ( )
72+ . name ( "rfd_file_write" . into ( ) )
73+ . spawn ( move || {
74+ tx. send ( std:: fs:: write ( path, bytes) ) . unwrap ( ) ;
75+ } )
76+ . unwrap ( ) ;
77+
78+ match rx. await {
79+ Ok ( res) => res,
80+ Err ( _) => Err ( io:: Error :: other ( "Write tread panicked" ) ) ,
81+ }
15682 }
15783
15884 /// Unwraps a `FileHandle` and returns inner type.
@@ -193,3 +119,24 @@ impl From<&FileHandle> for PathBuf {
193119 PathBuf :: from ( file_handle. path ( ) )
194120 }
195121}
122+
123+ #[ cfg( test) ]
124+ mod tests {
125+ use super :: * ;
126+
127+ #[ cfg( target_family = "unix" ) ]
128+ #[ test]
129+ fn write_and_read ( ) {
130+ futures:: executor:: block_on ( async {
131+ let path = "/tmp/rfd_test_write_read.txt" ;
132+ let handle = FileHandle ( path. into ( ) ) ;
133+
134+ handle. write ( b"Hello world" ) . await . unwrap ( ) ;
135+ let bytes = handle. read ( ) . await ;
136+
137+ assert_eq ! ( bytes, b"Hello world" ) ;
138+
139+ std:: fs:: remove_file ( path) . unwrap ( ) ;
140+ } ) ;
141+ }
142+ }
0 commit comments