vyder_std 0.3.4

Standard library for vyder.
Documentation
//! Various functions to read and write.
//!
//! Available under the name `std-io`.

use std::{io::Write, process::ExitCode};

use vyder::{values, Error, ExpectArity, Module, Span, Value, ValueResult};

/// Read the file at the given path and return it's contents.
///
/// Expects exactly one argument.
pub fn read_file(
    arguments: &[ValueResult],
    span: Span,
) -> Result<(ValueResult, Option<ExitCode>), Error> {
    let file_path = arguments.to_vec().expect_exact::<1>(&span)?[0]
        .clone()
        .expect_non_error()?
        .expect::<values::Str>()?
        .value;

    match std::fs::read_to_string(file_path) {
        Ok(file_contents) => Ok((
            Value::new_ok_value(
                values::Str {
                    value: file_contents,
                }
                .into(),
                span,
            ),
            None,
        )),
        Err(_) => Ok((
            Value::new_err_value(
                values::Str {
                    value: "failed to read the file".to_string(),
                }
                .into(),
                span,
            ),
            None,
        )),
    }
}

/// Write given contents to the file at the given path.
///
/// Expects the file path as the first argument and the contents as the second argument.
pub fn write_file(
    arguments: &[ValueResult],
    span: Span,
) -> Result<(ValueResult, Option<ExitCode>), Error> {
    let arguments = arguments.to_vec().expect_exact::<2>(&span)?.clone();
    let file_path = arguments[0]
        .clone()
        .expect_non_error()?
        .expect::<values::Str>()?
        .value;
    let file_contents = arguments[1].clone().expect_non_error()?.value.to_string();

    let mut file = match std::fs::File::create(file_path) {
        Ok(file) => file,
        Err(_) => {
            return Ok((
                Value::new_err_value(
                    values::Str {
                        value: "failed to open the file".to_string(),
                    }
                    .into(),
                    span,
                ),
                None,
            ))
        }
    };

    match file.write_all(file_contents.as_bytes()) {
        Ok(_) => Ok((Value::new_ok_value(values::Nil.into(), span), None)),
        Err(_) => Ok((
            Value::new_err_value(
                values::Str {
                    value: "failed to write to the file".to_string(),
                }
                .into(),
                span,
            ),
            None,
        )),
    }
}

/// Read stdio until `\n`.
///
/// Returns the read input as a string.
pub fn input(
    arguments: &[ValueResult],
    span: Span,
) -> Result<(ValueResult, Option<ExitCode>), Error> {
    let prompt = arguments.to_vec().expect_exact::<1>(&span)?[0]
        .clone()
        .expect_non_error()?
        .value
        .to_string();

    let stdout = &mut std::io::stdout();
    let stdin = std::io::stdin();

    print!("{}", prompt);

    stdout.flush().unwrap();
    let mut user_input = String::new();
    stdin.read_line(&mut user_input).unwrap();

    Ok((
        Value::new_ok_value(values::Str { value: user_input }.into(), span),
        None,
    ))
}

pub fn get_module() -> Module {
    Module::builder()
        .function("read_file", read_file, true)
        .function("write_file", write_file, true)
        .function("input", input, false)
        .build()
}