lang_interpreter/interpreter/
platform.rs1#[cfg(feature = "wasm-platform-api")]
2#[doc(hidden)]
3pub mod wasm;
4#[cfg(feature = "wasm-platform-api")]
5#[doc(inline)]
6pub use wasm::WASMPlatformAPI;
7
8use std::collections::HashMap;
9use std::ffi::OsString;
10use std::fmt::Debug;
11use std::{fs, io};
12use std::fs::File;
13use std::io::{Error, Read, Write};
14use std::path::{Path, PathBuf};
15use crate::interpreter::data::function::native::NativeError;
16
17pub trait PlatformAPI: Debug {
19 fn get_lang_files(&self, lang_path: &Path) -> Result<Vec<PathBuf>, Error>;
25
26 fn get_lang_path(&self, lang_file: &Path) -> Result<PathBuf, Error>;
32
33 fn get_lang_file_name(&self, lang_file: &Path) -> Option<OsString>;
39
40 fn get_lang_reader(&self, lang_file: &Path) -> Result<Box<[u8]>, Error>;
46
47 fn write_lang_file(&self, lang_file: &Path, translation_map: HashMap<String, String>) -> Result<(), Error>;
54
55 fn show_input_dialog(&self, text: &str) -> Result<String, NativeError>;
61
62 fn print(&mut self, text: &str) {
68 print!("{text}");
69 let _ = io::stdout().flush();
70 }
71
72 fn println(&mut self, text: &str) {
78 println!("{text}");
79 }
80
81 fn print_error(&mut self, text: &str) {
87 eprint!("{text}");
88 let _ = io::stderr().flush();
89 }
90
91 fn println_error(&mut self, text: &str) {
97 eprintln!("{text}");
98 }
99}
100
101#[derive(Debug)]
106pub struct DefaultPlatformAPI;
107
108impl DefaultPlatformAPI {
109 pub fn new() -> Self {
110 Self
111 }
112}
113
114impl Default for DefaultPlatformAPI {
115 fn default() -> Self {
116 Self::new()
117 }
118}
119
120impl PlatformAPI for DefaultPlatformAPI {
121 fn get_lang_files(&self, lang_path: &Path) -> Result<Vec<PathBuf>, Error> {
122 let files = fs::read_dir(lang_path)?;
123
124 let mut lang_files = Vec::new();
125
126 for file in files {
127 let file = file?;
128 let file_type = file.file_type()?;
129 if !file_type.is_dir() {
130 let file_name = file.file_name();
131 if let Some(file_name) = file_name.to_str()
132 && file_name.to_ascii_lowercase().ends_with(".lang") {
133 lang_files.push(file.path());
134 }
135 }
136 }
137
138 Ok(lang_files)
139 }
140
141 fn get_lang_path(&self, lang_file: &Path) -> Result<PathBuf, Error> {
142 let path = lang_file;
143 let mut path = path.parent().unwrap_or(Path::new(""));
144 if path == Path::new("") {
145 path = Path::new("./");
146 }
147
148 let canonical_path = path.canonicalize();
149 if let Ok(canonical_path) = canonical_path {
150 Ok(canonical_path)
151 }else {
152 std::path::absolute(path)
153 }
154 }
155
156 fn get_lang_file_name(&self, lang_file: &Path) -> Option<OsString> {
157 let path = lang_file;
158
159 path.file_name().map(|str| str.to_os_string())
160 }
161
162 fn get_lang_reader(&self, lang_file: &Path) -> Result<Box<[u8]>, Error> {
163 let path = lang_file;
164
165 let mut file = File::open(path)?;
166
167 let mut bytes = Vec::new();
168 file.read_to_end(&mut bytes)?;
169
170 Ok(bytes.into_boxed_slice())
171 }
172
173 fn write_lang_file(&self, lang_file: &Path, translation_map: HashMap<String, String>) -> Result<(), Error> {
174 let path = lang_file;
175
176 let mut file = File::create(path)?;
177
178 for (translation_key, translation_value) in translation_map {
179 let translation_value = translation_value.replace("\n", "\\n");
181
182 writeln!(file, "{translation_key} = {translation_value}")?;
183 }
184
185 Ok(())
186 }
187
188 fn show_input_dialog(&self, _text: &str) -> Result<String, NativeError> {
192 Err(NativeError::new(
193 "Not Implemented",
194 None,
195 ))
196 }
197}