tauri_plugin_android_fs/api/
writable_stream.rs

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