1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use std::borrow::Cow;
use std::error;
use std::fmt;
use std::io;

use crate::core::{ClassRegistry, Io, TryConvertMut};
use crate::error::{Error, RubyException};
use crate::extn::core::exception;
use crate::ffi::InterpreterExtractError;
use crate::state::output::Output;
use crate::sys;
use crate::Artichoke;

impl Io for Artichoke {
    type Error = Error;

    /// Writes the given bytes to the interpreter stdout stream.
    ///
    /// This implementation delegates to the underlying output strategy.
    ///
    /// # Errors
    ///
    /// If the output stream encounters an error, an error is returned.
    fn print<T: AsRef<[u8]>>(&mut self, message: T) -> Result<(), Self::Error> {
        let state = self.state.as_deref_mut().ok_or_else(InterpreterExtractError::new)?;
        state.output.write_stdout(message.as_ref())?;
        Ok(())
    }

    /// Writes the given bytes to the interpreter stdout stream followed by a
    /// newline.
    ///
    /// This implementation delegates to the underlying output strategy.
    ///
    /// # Errors
    ///
    /// If the output stream encounters an error, an error is returned.
    fn puts<T: AsRef<[u8]>>(&mut self, message: T) -> Result<(), Self::Error> {
        let state = self.state.as_deref_mut().ok_or_else(InterpreterExtractError::new)?;
        state.output.write_stdout(message.as_ref())?;
        state.output.write_stdout(b"\n")?;
        Ok(())
    }
}

#[derive(Debug)]
#[allow(clippy::module_name_repetitions)]
pub struct IoError(io::Error);

impl From<io::Error> for IoError {
    fn from(err: io::Error) -> Self {
        Self(err)
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Self {
        Self::from(IoError::from(err))
    }
}

impl fmt::Display for IoError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "IOError: {}", self.0)
    }
}

impl error::Error for IoError {
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        Some(&self.0)
    }
}

impl RubyException for IoError {
    fn message(&self) -> Cow<'_, [u8]> {
        self.0.to_string().into_bytes().into()
    }

    fn name(&self) -> Cow<'_, str> {
        "IOError".into()
    }

    fn vm_backtrace(&self, interp: &mut Artichoke) -> Option<Vec<Vec<u8>>> {
        let _ = interp;
        None
    }

    fn as_mrb_value(&self, interp: &mut Artichoke) -> Option<sys::mrb_value> {
        let message = interp.try_convert_mut(self.message()).ok()?;
        let value = interp.new_instance::<exception::IOError>(&[message]).ok().flatten()?;
        Some(value.inner())
    }
}

impl From<IoError> for Error {
    fn from(exception: IoError) -> Self {
        Self::from(Box::<dyn RubyException>::from(exception))
    }
}

impl From<Box<IoError>> for Error {
    fn from(exception: Box<IoError>) -> Self {
        Self::from(Box::<dyn RubyException>::from(exception))
    }
}

impl From<IoError> for Box<dyn RubyException> {
    fn from(exception: IoError) -> Box<dyn RubyException> {
        Box::new(exception)
    }
}

impl From<Box<IoError>> for Box<dyn RubyException> {
    fn from(exception: Box<IoError>) -> Box<dyn RubyException> {
        exception
    }
}