jimtcl 0.3.0

Embed Jim Tcl in Rust.
Documentation
//! Jim Tcl errors.
use std::{convert::Infallible, error::Error, ffi, os::raw::c_int, str};

use crate::sys;
use parse_display::Display;
use thiserror::Error;

/// Wrapper for Jim error codes.
#[derive(Debug, Display, Clone)]
#[repr(u32)]
pub enum ExitCode {
    Ok = sys::JIM_OK,
    Err = sys::JIM_ERR,
    Return = sys::JIM_RETURN,
    Break = sys::JIM_BREAK,
    Continue = sys::JIM_CONTINUE,
    Signal = sys::JIM_SIGNAL,
    Exit = sys::JIM_EXIT,
    #[display("format")]
    InvalidCode(u32),
}

impl From<u32> for ExitCode {
    fn from(value: u32) -> Self {
        match value {
            sys::JIM_OK => ExitCode::Ok,
            sys::JIM_ERR => ExitCode::Err,
            sys::JIM_RETURN => ExitCode::Return,
            sys::JIM_BREAK => ExitCode::Break,
            sys::JIM_CONTINUE => ExitCode::Continue,
            sys::JIM_SIGNAL => ExitCode::Signal,
            sys::JIM_EXIT => ExitCode::Exit,
            x => ExitCode::InvalidCode(x),
        }
    }
}

impl Into<c_int> for ExitCode {
    fn into(self) -> c_int {
        let ec: u32 = self.into();
        ec as c_int
    }
}

impl Into<u32> for ExitCode {
    fn into(self) -> u32 {
        match self {
            ExitCode::Ok => sys::JIM_OK,
            ExitCode::Err => sys::JIM_ERR,
            ExitCode::Return => sys::JIM_RETURN,
            ExitCode::Break => sys::JIM_BREAK,
            ExitCode::Continue => sys::JIM_CONTINUE,
            ExitCode::Signal => sys::JIM_SIGNAL,
            ExitCode::Exit => sys::JIM_EXIT,
            ExitCode::InvalidCode(c) => c,
        }
    }
}

/// Error type Jim Tcl results.
#[derive(Error, Debug)]
pub enum JimError {
    #[error("Tcl evaluation error: {0}")]
    Error(String),
    #[error("Tcl return code {0}")]
    OtherCode(ExitCode),
    #[error("Jim object is null")]
    NullObject,
    #[error("index {0} is out of bounds")]
    InvalidIndex(usize),
    #[error("object is not a dictionary")]
    InvalidDictionary,
    #[error("Input string has null character")]
    NullCharacter,
    #[error("String is not valid UTF-8")]
    InvalidUtf8,
    #[error("{0}")]
    Wrapped(Box<dyn Error>),
}

impl JimError {
    /// Wrap another error in a Jim error.
    pub fn wrap<E: Error + 'static>(err: E) -> JimError {
        JimError::Wrapped(Box::new(err))
    }
}

impl From<&str> for JimError {
    fn from(value: &str) -> Self {
        JimError::Error(value.to_owned())
    }
}

impl From<String> for JimError {
    fn from(value: String) -> Self {
        JimError::Error(value)
    }
}

impl From<Infallible> for JimError {
    fn from(_value: Infallible) -> Self {
        unreachable!("infallible error")
    }
}

impl From<ffi::NulError> for JimError {
    fn from(_value: ffi::NulError) -> Self {
        JimError::NullCharacter
    }
}

impl From<str::Utf8Error> for JimError {
    fn from(_: str::Utf8Error) -> Self {
        JimError::InvalidUtf8
    }
}

/// Result of a Jim Tcl error.
pub type JimResult<T> = Result<T, JimError>;