tenda-os-platform 0.1.0

Operating system platform support for the Tenda programming language
Documentation
use chrono::Local;
use std::io::Write;

#[derive(Debug)]
pub struct Platform;

fn map_file_error_kind(kind: std::io::ErrorKind) -> tenda_runtime::FileErrorKind {
    use std::io;
    use tenda_runtime::FileErrorKind;

    match kind {
        io::ErrorKind::NotFound => FileErrorKind::NotFound,
        io::ErrorKind::PermissionDenied => FileErrorKind::PermissionDenied,
        io::ErrorKind::AlreadyExists => FileErrorKind::AlreadyExists,
        io::ErrorKind::Other => FileErrorKind::Other,
        _ => FileErrorKind::Other,
    }
}

impl tenda_runtime::Platform for Platform {
    fn println(&self, message: &str) {
        println!("{}", message);
    }

    fn print(&self, message: &str) {
        print!("{}", message);

        std::io::stdout().flush().unwrap();
    }

    fn write(&self, message: &str) {
        print!("{}", message);
    }

    fn rand(&self) -> f64 {
        rand::random()
    }

    fn read_file(&self, path: &str) -> Result<String, tenda_runtime::FileErrorKind> {
        match std::fs::read_to_string(path) {
            Ok(content) => Ok(content),
            Err(error) => Err(map_file_error_kind(error.kind())),
        }
    }

    fn write_file(&self, path: &str, content: &str) -> Result<(), tenda_runtime::FileErrorKind> {
        match std::fs::write(path, content) {
            Ok(_) => Ok(()),
            Err(error) => Err(map_file_error_kind(error.kind())),
        }
    }

    fn remove_file(&self, path: &str) -> Result<(), tenda_runtime::FileErrorKind> {
        match std::fs::remove_file(path) {
            Ok(_) => Ok(()),
            Err(error) => Err(map_file_error_kind(error.kind())),
        }
    }

    fn list_files(&self, path: &str) -> Result<Vec<String>, tenda_runtime::FileErrorKind> {
        match std::fs::read_dir(path) {
            Ok(entries) => Ok(entries
                .filter_map(|entry| entry.ok().map(|entry| entry.file_name()))
                .map(|name| name.to_string_lossy().to_string())
                .collect()),
            Err(error) => Err(map_file_error_kind(error.kind())),
        }
    }

    fn create_dir(&self, path: &str) -> Result<(), tenda_runtime::FileErrorKind> {
        match std::fs::create_dir(path) {
            Ok(_) => Ok(()),
            Err(error) => Err(map_file_error_kind(error.kind())),
        }
    }

    fn remove_dir(&self, path: &str) -> Result<(), tenda_runtime::FileErrorKind> {
        match std::fs::remove_dir(path) {
            Ok(_) => Ok(()),
            Err(error) => Err(map_file_error_kind(error.kind())),
        }
    }

    fn list_dirs(&self, path: &str) -> Result<Vec<String>, tenda_runtime::FileErrorKind> {
        match std::fs::read_dir(path) {
            Ok(entries) => Ok(entries
                .filter_map(|entry| entry.ok().map(|entry| entry.file_name()))
                .map(|name| name.to_string_lossy().to_string())
                .collect()),
            Err(error) => Err(map_file_error_kind(error.kind())),
        }
    }

    fn current_dir(&self) -> Result<String, tenda_runtime::FileErrorKind> {
        match std::env::current_dir() {
            Ok(path) => Ok(path.to_string_lossy().to_string()),
            Err(error) => Err(map_file_error_kind(error.kind())),
        }
    }

    fn file_append(&self, path: &str, content: &str) -> Result<(), tenda_runtime::FileErrorKind> {
        match std::fs::OpenOptions::new().append(true).open(path) {
            Ok(mut file) => match file.write_all(content.as_bytes()) {
                Ok(_) => Ok(()),
                Err(error) => Err(map_file_error_kind(error.kind())),
            },
            Err(error) => Err(map_file_error_kind(error.kind())),
        }
    }

    fn args(&self) -> Vec<String> {
        std::env::args().collect()
    }

    fn exit(&self, code: i32) {
        std::process::exit(code);
    }

    fn sleep(&self, seconds: f64) {
        std::thread::sleep(std::time::Duration::from_secs_f64(seconds));
    }

    fn date_now(&self) -> i64 {
        Local::now().timestamp_millis()
    }

    fn timezone_offset(&self) -> i32 {
        Local::now().offset().local_minus_utc()
    }

    fn read_line(&self) -> String {
        let mut input = String::new();
        std::io::stdin().read_line(&mut input).unwrap();
        input.trim_end().to_string()
    }
}