use std::fmt;
#[cfg(ruby_lt_3_3)]
use std::ptr::NonNull;
#[cfg(ruby_gte_3_3)]
use rb_sys::rb_io_descriptor;
use rb_sys::ruby_value_type;
use crate::{
error::Error,
into_value::IntoValue,
object::Object,
try_convert::TryConvert,
value::{
private::{self, ReprValue as _},
NonZeroValue, ReprValue, Value,
},
Ruby,
};
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct RFile(NonZeroValue);
impl RFile {
#[inline]
pub fn from_value(val: Value) -> Option<Self> {
unsafe {
(val.rb_type() == ruby_value_type::RUBY_T_FILE)
.then(|| Self(NonZeroValue::new_unchecked(val)))
}
}
#[cfg(ruby_lt_3_3)]
fn as_internal(self) -> NonNull<rb_sys::RFile> {
unsafe { NonNull::new_unchecked(self.0.get().as_rb_value() as *mut _) }
}
}
impl fmt::Display for RFile {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", unsafe { self.to_s_infallible() })
}
}
impl fmt::Debug for RFile {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.inspect())
}
}
impl IntoValue for RFile {
#[inline]
fn into_value_with(self, _: &Ruby) -> Value {
self.0.get()
}
}
impl Object for RFile {}
unsafe impl private::ReprValue for RFile {}
impl ReprValue for RFile {}
impl TryConvert for RFile {
fn try_convert(val: Value) -> Result<Self, Error> {
Self::from_value(val).ok_or_else(|| {
Error::new(
Ruby::get_with(val).exception_type_error(),
format!("no implicit conversion of {} into File", unsafe {
val.classname()
},),
)
})
}
}
#[cfg(not(unix))]
pub mod fd {
use std::os::raw::c_int;
pub type RawFd = c_int;
pub trait AsRawFd {
fn as_raw_fd(&self) -> RawFd;
}
}
#[cfg(unix)]
pub use std::os::unix::io as fd;
impl fd::AsRawFd for RFile {
#[cfg(ruby_gte_3_3)]
fn as_raw_fd(&self) -> fd::RawFd {
unsafe { rb_io_descriptor(self.as_rb_value()) }
}
#[cfg(ruby_lt_3_3)]
fn as_raw_fd(&self) -> fd::RawFd {
unsafe { (*self.as_internal().as_ref().fptr).fd }
}
}