Thanks to visit codestin.com
Credit goes to docs.rs

magnus/
r_file.rs

1use std::fmt;
2#[cfg(ruby_lt_3_3)]
3use std::ptr::NonNull;
4
5#[cfg(ruby_gte_3_3)]
6use rb_sys::rb_io_descriptor;
7use rb_sys::ruby_value_type;
8
9use crate::{
10    error::Error,
11    into_value::IntoValue,
12    object::Object,
13    try_convert::TryConvert,
14    value::{
15        private::{self, ReprValue as _},
16        NonZeroValue, ReprValue, Value,
17    },
18    Ruby,
19};
20
21/// A Value pointer to a RFile struct, Ruby's internal representation of IO.
22///
23/// See the [`ReprValue`] and [`Object`] traits for additional methods
24/// available on this type.
25#[derive(Clone, Copy)]
26#[repr(transparent)]
27pub struct RFile(NonZeroValue);
28
29impl RFile {
30    /// Return `Some(RFile)` if `val` is a `RFile`, `None` otherwise.
31    ///
32    /// # Examples
33    ///
34    /// ```
35    /// use magnus::{eval, RFile};
36    /// # let ruby = unsafe { magnus::embed::init() };
37    ///
38    /// assert!(RFile::from_value(eval("STDOUT").unwrap()).is_some());
39    /// # #[cfg(not(windows))]
40    /// # {
41    /// assert!(RFile::from_value(eval(r#"File.open("/tmp/example.txt", "w+")"#).unwrap()).is_some());
42    /// # ruby.require("socket").unwrap();
43    /// assert!(RFile::from_value(eval("UNIXSocket.pair.first").unwrap()).is_some());
44    /// # }
45    /// assert!(RFile::from_value(eval("nil").unwrap()).is_none());
46    /// ```
47    #[inline]
48    pub fn from_value(val: Value) -> Option<Self> {
49        unsafe {
50            (val.rb_type() == ruby_value_type::RUBY_T_FILE)
51                .then(|| Self(NonZeroValue::new_unchecked(val)))
52        }
53    }
54
55    #[cfg(ruby_lt_3_3)]
56    fn as_internal(self) -> NonNull<rb_sys::RFile> {
57        // safe as inner value is NonZero
58        unsafe { NonNull::new_unchecked(self.0.get().as_rb_value() as *mut _) }
59    }
60}
61
62impl fmt::Display for RFile {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        write!(f, "{}", unsafe { self.to_s_infallible() })
65    }
66}
67
68impl fmt::Debug for RFile {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        write!(f, "{}", self.inspect())
71    }
72}
73
74impl IntoValue for RFile {
75    #[inline]
76    fn into_value_with(self, _: &Ruby) -> Value {
77        self.0.get()
78    }
79}
80
81impl Object for RFile {}
82
83unsafe impl private::ReprValue for RFile {}
84
85impl ReprValue for RFile {}
86
87impl TryConvert for RFile {
88    fn try_convert(val: Value) -> Result<Self, Error> {
89        Self::from_value(val).ok_or_else(|| {
90            Error::new(
91                Ruby::get_with(val).exception_type_error(),
92                format!("no implicit conversion of {} into File", unsafe {
93                    val.classname()
94                },),
95            )
96        })
97    }
98}
99
100#[cfg(not(unix))]
101pub mod fd {
102    use std::os::raw::c_int;
103
104    pub type RawFd = c_int;
105
106    pub trait AsRawFd {
107        fn as_raw_fd(&self) -> RawFd;
108    }
109}
110
111#[cfg(unix)]
112pub use std::os::unix::io as fd;
113
114impl fd::AsRawFd for RFile {
115    #[cfg(ruby_gte_3_3)]
116    fn as_raw_fd(&self) -> fd::RawFd {
117        unsafe { rb_io_descriptor(self.as_rb_value()) }
118    }
119    #[cfg(ruby_lt_3_3)]
120    fn as_raw_fd(&self) -> fd::RawFd {
121        unsafe { (*self.as_internal().as_ref().fptr).fd }
122    }
123}