1use std::{io::Error, path::Path};
22
23#[derive(Debug)]
24pub enum FileLoadError {
25 Io(std::io::Error),
26 Custom(String),
27}
28
29impl From<std::io::Error> for FileLoadError {
30 fn from(e: Error) -> Self {
31 Self::Io(e)
32 }
33}
34
35#[cfg(target_os = "android")]
36pub static ANDROID_APP: once_cell::sync::OnceCell<android_activity::AndroidApp> =
37 once_cell::sync::OnceCell::new();
38
39#[cfg(target_arch = "wasm32")]
40impl From<wasm_bindgen::JsValue> for FileLoadError {
41 fn from(value: wasm_bindgen::JsValue) -> Self {
42 let string = match js_sys::JSON::stringify(&value) {
43 Ok(string) => String::from(string),
44 Err(_) => format!("{:?}", value),
45 };
46 Self::Custom(string)
47 }
48}
49
50pub async fn load_file<P: AsRef<Path>>(path: P) -> Result<Vec<u8>, FileLoadError> {
51 #[cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))]
52 {
53 use std::fs::File;
54 use std::io::Read;
55
56 let mut file = File::open(path)?;
57 let mut buffer = Vec::new();
58 file.read_to_end(&mut buffer)?;
59 Ok(buffer)
60 }
61
62 #[cfg(target_os = "android")]
63 {
64 let asset_manager = ANDROID_APP
65 .get()
66 .ok_or_else(|| FileLoadError::Custom("ANDROID_APP is not set".to_string()))?
67 .asset_manager();
68 let mut opened_asset = asset_manager
69 .open(&std::ffi::CString::new(path.as_ref().to_str().unwrap()).unwrap())
70 .ok_or_else(|| FileLoadError::Custom(format!("File {:?} not found!", path.as_ref())))?;
71 let bytes = opened_asset.buffer()?;
72 Ok(bytes.to_vec())
73 }
74
75 #[cfg(target_arch = "wasm32")]
76 {
77 use js_sys::Uint8Array;
78 use wasm_bindgen::JsCast;
79 use wasm_bindgen_futures::JsFuture;
80
81 match web_sys::window() {
82 Some(window) => {
83 let resp_value =
84 JsFuture::from(window.fetch_with_str(path.as_ref().to_str().unwrap())).await?;
85
86 let resp: web_sys::Response = resp_value.dyn_into().unwrap();
87 let data = JsFuture::from(resp.array_buffer().unwrap()).await?;
88 let bytes = Uint8Array::new(&data).to_vec();
89 Ok(bytes)
90 }
91 None => Err(FileLoadError::Custom("Window not found!".to_owned())),
92 }
93 }
94}
95
96pub async fn exists<P: AsRef<Path>>(path: P) -> bool {
97 #[cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))]
98 {
99 path.as_ref().exists()
100 }
101
102 #[cfg(target_os = "android")]
103 {
104 ANDROID_APP
105 .get()
106 .map(|v| {
107 v.asset_manager()
108 .open(&std::ffi::CString::new(path.as_ref().to_str().unwrap()).unwrap())
109 .is_some()
110 })
111 .unwrap_or_default()
112 }
113
114 #[cfg(target_arch = "wasm32")]
115 {
116 use wasm_bindgen::JsCast;
117 use wasm_bindgen_futures::JsFuture;
118
119 match web_sys::window() {
120 Some(window) => {
121 if let Ok(resp_value) =
122 JsFuture::from(window.fetch_with_str(path.as_ref().to_str().unwrap())).await
123 {
124 let resp: web_sys::Response = resp_value.dyn_into().unwrap();
125
126 resp.status() == 200
127 } else {
128 false
129 }
130 }
131 None => false,
132 }
133 }
134}
135
136pub async fn is_dir<P: AsRef<Path>>(#[allow(unused)] path: P) -> bool {
137 #[cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))]
138 {
139 path.as_ref().is_dir()
140 }
141
142 #[cfg(target_os = "android")]
143 {
144 ANDROID_APP
145 .get()
146 .map(|v| {
147 v.asset_manager()
148 .open_dir(&std::ffi::CString::new(path.as_ref().to_str().unwrap()).unwrap())
149 .is_some()
150 })
151 .unwrap_or_default()
152 }
153
154 #[cfg(target_arch = "wasm32")]
156 {
157 false
158 }
159}
160
161pub async fn is_file<P: AsRef<Path>>(path: P) -> bool {
162 #[cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))]
163 {
164 path.as_ref().is_file()
165 }
166
167 #[cfg(any(target_os = "android", target_arch = "wasm32"))]
169 {
170 exists(path).await
171 }
172}