sapphire-lang 0.8.0

Gradually typed scripting language where every value is an object and types are optional, checked at runtime
Documentation
use std::collections::HashMap;
use std::io::{BufRead, BufReader, Read, Write};
use std::net::TcpStream;

use crate::vm::{VmError, VmValue};

fn raise(msg: impl Into<String>) -> VmError {
    VmError::Raised(VmValue::Str(msg.into()))
}

pub fn socket_connect(host: &str, port: i64, _line: u32) -> Result<BufReader<TcpStream>, VmError> {
    TcpStream::connect(format!("{}:{}", host, port))
        .map(BufReader::new)
        .map_err(|e| raise(format!("Socket.connect: {}", e)))
}

pub fn socket_write(reader: &mut BufReader<TcpStream>, data: &str, _line: u32) -> Result<(), VmError> {
    reader
        .get_mut()
        .write_all(data.as_bytes())
        .map_err(|e| raise(format!("socket.write: {}", e)))
}

pub fn socket_read_line(reader: &mut BufReader<TcpStream>, _line: u32) -> Result<String, VmError> {
    let mut buf = String::new();
    reader
        .read_line(&mut buf)
        .map_err(|e| raise(format!("socket.read_line: {}", e)))?;
    if buf.ends_with('\n') {
        buf.pop();
        if buf.ends_with('\r') {
            buf.pop();
        }
    }
    Ok(buf)
}

pub fn socket_read_bytes(reader: &mut BufReader<TcpStream>, n: i64, _line: u32) -> Result<String, VmError> {
    let n = n.max(0) as usize;
    let mut buf = vec![0u8; n];
    reader
        .read_exact(&mut buf)
        .map_err(|e| raise(format!("socket.read_bytes: {}", e)))?;
    Ok(String::from_utf8_lossy(&buf).into_owned())
}

pub fn socket_read_all(reader: &mut BufReader<TcpStream>, _line: u32) -> Result<String, VmError> {
    let mut buf = String::new();
    reader
        .read_to_string(&mut buf)
        .map_err(|e| raise(format!("socket.read_all: {}", e)))?;
    Ok(buf)
}

pub fn extract_fd(fields: &HashMap<String, VmValue>, line: u32) -> Result<i64, VmError> {
    match fields.get("fd") {
        Some(VmValue::Int(n)) => Ok(*n),
        _ => Err(VmError::TypeError {
            message: "socket instance has invalid fd".into(),
            line,
        }),
    }
}