1use chrono::Local;
2use std::io::Write;
3
4#[derive(Debug)]
5pub struct Platform;
6
7fn map_file_error_kind(kind: std::io::ErrorKind) -> tenda_runtime::FileErrorKind {
8 use std::io;
9 use tenda_runtime::FileErrorKind;
10
11 match kind {
12 io::ErrorKind::NotFound => FileErrorKind::NotFound,
13 io::ErrorKind::PermissionDenied => FileErrorKind::PermissionDenied,
14 io::ErrorKind::AlreadyExists => FileErrorKind::AlreadyExists,
15 io::ErrorKind::Other => FileErrorKind::Other,
16 _ => FileErrorKind::Other,
17 }
18}
19
20impl tenda_runtime::Platform for Platform {
21 fn println(&self, message: &str) {
22 println!("{}", message);
23 }
24
25 fn print(&self, message: &str) {
26 print!("{}", message);
27
28 std::io::stdout().flush().unwrap();
29 }
30
31 fn write(&self, message: &str) {
32 print!("{}", message);
33 }
34
35 fn rand(&self) -> f64 {
36 rand::random()
37 }
38
39 fn read_file(&self, path: &str) -> Result<String, tenda_runtime::FileErrorKind> {
40 match std::fs::read_to_string(path) {
41 Ok(content) => Ok(content),
42 Err(error) => Err(map_file_error_kind(error.kind())),
43 }
44 }
45
46 fn write_file(&self, path: &str, content: &str) -> Result<(), tenda_runtime::FileErrorKind> {
47 match std::fs::write(path, content) {
48 Ok(_) => Ok(()),
49 Err(error) => Err(map_file_error_kind(error.kind())),
50 }
51 }
52
53 fn remove_file(&self, path: &str) -> Result<(), tenda_runtime::FileErrorKind> {
54 match std::fs::remove_file(path) {
55 Ok(_) => Ok(()),
56 Err(error) => Err(map_file_error_kind(error.kind())),
57 }
58 }
59
60 fn list_files(&self, path: &str) -> Result<Vec<String>, tenda_runtime::FileErrorKind> {
61 match std::fs::read_dir(path) {
62 Ok(entries) => Ok(entries
63 .filter_map(|entry| entry.ok().map(|entry| entry.file_name()))
64 .map(|name| name.to_string_lossy().to_string())
65 .collect()),
66 Err(error) => Err(map_file_error_kind(error.kind())),
67 }
68 }
69
70 fn create_dir(&self, path: &str) -> Result<(), tenda_runtime::FileErrorKind> {
71 match std::fs::create_dir(path) {
72 Ok(_) => Ok(()),
73 Err(error) => Err(map_file_error_kind(error.kind())),
74 }
75 }
76
77 fn remove_dir(&self, path: &str) -> Result<(), tenda_runtime::FileErrorKind> {
78 match std::fs::remove_dir(path) {
79 Ok(_) => Ok(()),
80 Err(error) => Err(map_file_error_kind(error.kind())),
81 }
82 }
83
84 fn list_dirs(&self, path: &str) -> Result<Vec<String>, tenda_runtime::FileErrorKind> {
85 match std::fs::read_dir(path) {
86 Ok(entries) => Ok(entries
87 .filter_map(|entry| entry.ok().map(|entry| entry.file_name()))
88 .map(|name| name.to_string_lossy().to_string())
89 .collect()),
90 Err(error) => Err(map_file_error_kind(error.kind())),
91 }
92 }
93
94 fn current_dir(&self) -> Result<String, tenda_runtime::FileErrorKind> {
95 match std::env::current_dir() {
96 Ok(path) => Ok(path.to_string_lossy().to_string()),
97 Err(error) => Err(map_file_error_kind(error.kind())),
98 }
99 }
100
101 fn file_append(&self, path: &str, content: &str) -> Result<(), tenda_runtime::FileErrorKind> {
102 match std::fs::OpenOptions::new().append(true).open(path) {
103 Ok(mut file) => match file.write_all(content.as_bytes()) {
104 Ok(_) => Ok(()),
105 Err(error) => Err(map_file_error_kind(error.kind())),
106 },
107 Err(error) => Err(map_file_error_kind(error.kind())),
108 }
109 }
110
111 fn args(&self) -> Vec<String> {
112 std::env::args().collect()
113 }
114
115 fn exit(&self, code: i32) {
116 std::process::exit(code);
117 }
118
119 fn sleep(&self, seconds: f64) {
120 std::thread::sleep(std::time::Duration::from_secs_f64(seconds));
121 }
122
123 fn date_now(&self) -> i64 {
124 Local::now().timestamp_millis()
125 }
126
127 fn timezone_offset(&self) -> i32 {
128 Local::now().offset().local_minus_utc()
129 }
130
131 fn read_line(&self) -> String {
132 let mut input = String::new();
133 std::io::stdin().read_line(&mut input).unwrap();
134 input.trim_end().to_string()
135 }
136}