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#[derive(Clone, Copy)]
26#[repr(transparent)]
27pub struct RFile(NonZeroValue);
28
29impl RFile {
30 #[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 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}