tauri_plugin_android_fs/api/
writable_stream.rs

1use sync_async::sync_async;
2use crate::*;
3use super::*;
4
5
6/// A stream for writing to a file on Android.
7///
8/// Implements [`std::io::Write`], so it can be used for writing.  
9/// As with [`std::fs::File`], wrap it with [`std::io::BufWriter`] if buffering is needed.  
10///
11/// After writing, call [`WritableStream::reflect`] to apply changes.  
12///
13/// # Inner
14/// This is a wrapper around [`std::fs::File`].  
15/// In most cases, it points to the actual target file, but it may also refer to a temporary file.  
16/// For temporary files, calling [`WritableStream::reflect`] applies the changes to the actual target. 
17#[sync_async(
18    use(if_sync) impls::SyncWritableStreamImpls as WritableStreamImpls;
19    use(if_async) impls::AsyncWritableStreamImpls as WritableStreamImpls;
20    use(if_sync) api_sync::WritableStream;
21    use(if_async) api_async::WritableStream;
22)]
23pub struct WritableStream<R: tauri::Runtime> {
24    #[cfg(target_os = "android")]
25    pub(crate) impls: WritableStreamImpls<R>,
26
27    #[cfg(not(target_os = "android"))]
28    #[allow(unused)]
29    pub(crate) impls: std::marker::PhantomData<fn() -> R>
30}
31
32#[sync_async(
33    use(if_async) api_async::{AndroidFs, FileOpener, FilePicker, PrivateStorage, PublicStorage};
34    use(if_sync) api_sync::{AndroidFs, FileOpener, FilePicker, PrivateStorage, PublicStorage};
35)]
36impl<R: tauri::Runtime> WritableStream<R> {
37
38    /// Converts to a WritableStream for synchronous processing.
39    #[always_sync]
40    pub fn into_sync(self) -> SyncWritableStream<R> {
41        #[cfg(not(target_os = "android"))] {
42            // WritableStream を取得する関数は Android 以外だとエラーになる。
43            // そのためこれが呼び出されることはない
44            panic!("expected on Android")
45        }
46        #[cfg(target_os = "android")] {
47            SyncWritableStream { impls: self.impls.into_sync() }
48        }
49    }
50
51    /// Converts to a WritableStream for asynchronous processing.
52    #[always_sync]
53    pub fn into_async(self) -> AsyncWritableStream<R> {
54        #[cfg(not(target_os = "android"))] {
55            // WritableStream を取得する関数は Android 以外だとエラーになる。
56            // そのためこれが呼び出されることはない
57            panic!("expected on Android")
58        }
59        #[cfg(target_os = "android")] {
60            AsyncWritableStream { impls: self.impls.into_async() }
61        }
62    }
63
64    /// [`WritableStream`] is a wrapper around [`std::fs::File`].
65    /// In most cases, it points to the actual target file, but it may also refer to a temporary file.
66    ///
67    /// For actual target files, this function does nothing.
68    ///
69    /// For temporary files, calling this function applies the changes to the actual target, and remove the temporary file.
70    /// This may take as long as the write operation or even longer.
71    /// Note that if the file is located on cloud storage or similar, the function returns
72    /// without waiting for the uploading to complete.
73    /// 
74    /// If not called explicitly, the same process is performed asynchronously on drop, 
75    /// and all errors is are ignored. 
76    #[maybe_async]
77    pub fn reflect(self) -> Result<()> {
78        #[cfg(not(target_os = "android"))] {
79            Err(Error::NOT_ANDROID)
80        }
81        #[cfg(target_os = "android")] {
82            self.impls.reflect().await
83        }
84    }
85
86    /// [`WritableStream`] is a wrapper around [`std::fs::File`].  
87    /// In most cases, it points to the actual target file, but it may also refer to a temporary file.  
88    ///
89    /// For actual target files, calls [`std::fs::File::sync_all`].  
90    /// For temporary files, this function does nothing.  
91    #[maybe_async]
92    pub fn sync_all(&self) -> std::io::Result<()> {
93        #[cfg(not(target_os = "android"))] {
94            Err(std::io::Error::new(std::io::ErrorKind::Other, Error::NOT_ANDROID))
95        }
96        #[cfg(target_os = "android")] {
97            self.impls.sync_all().await
98        }
99    }
100
101    /// [`WritableStream`] is a wrapper around [`std::fs::File`].  
102    /// In most cases, it points to the actual target file, but it may also refer to a temporary file.  
103    ///
104    /// For actual target files, calls [`std::fs::File::sync_data`].  
105    /// For temporary files, this function does nothing.  
106    #[maybe_async]
107    pub fn sync_data(&self) -> std::io::Result<()> {
108        #[cfg(not(target_os = "android"))] {
109            Err(std::io::Error::new(std::io::ErrorKind::Other, Error::NOT_ANDROID))
110        }
111        #[cfg(target_os = "android")] {
112            self.impls.sync_data().await
113        }
114    }
115}
116
117macro_rules! impl_write {
118    ($target:ident) => {
119
120        impl<R: tauri::Runtime> std::io::Write for $target<R> {
121
122            fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
123                #[cfg(not(target_os = "android"))] {
124                    Err(std::io::Error::new(std::io::ErrorKind::Other, Error::NOT_ANDROID))
125                }
126                #[cfg(target_os = "android")] {
127                    self.impls.write(buf)
128                }
129            }
130
131            fn flush(&mut self) -> std::io::Result<()> {
132                #[cfg(not(target_os = "android"))] {
133                    Err(std::io::Error::new(std::io::ErrorKind::Other, Error::NOT_ANDROID))
134                }
135                #[cfg(target_os = "android")] {
136                    self.impls.flush()
137                }
138            }
139
140            fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
141                #[cfg(not(target_os = "android"))] {
142                    Err(std::io::Error::new(std::io::ErrorKind::Other, Error::NOT_ANDROID))
143                }
144                #[cfg(target_os = "android")] {
145                    self.impls.write_all(buf)
146                }
147            }
148
149            fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result<usize> {
150                #[cfg(not(target_os = "android"))] {
151                    Err(std::io::Error::new(std::io::ErrorKind::Other, Error::NOT_ANDROID))
152                }
153                #[cfg(target_os = "android")] {
154                    self.impls.write_vectored(bufs)
155                }
156            }
157
158            fn write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> std::io::Result<()> {
159                #[cfg(not(target_os = "android"))] {
160                    Err(std::io::Error::new(std::io::ErrorKind::Other, Error::NOT_ANDROID))
161                }
162                #[cfg(target_os = "android")] {
163                    self.impls.write_fmt(fmt)
164                }
165            }
166        }
167    };
168}
169
170impl_write!(AsyncWritableStream);
171impl_write!(SyncWritableStream);