crossterm/terminal/sys/
file_descriptor.rs1use std::io;
2
3#[cfg(feature = "libc")]
4use libc::size_t;
5#[cfg(not(feature = "libc"))]
6use rustix::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd};
7#[cfg(feature = "libc")]
8use std::{
9 fs,
10 marker::PhantomData,
11 os::unix::{
12 io::{IntoRawFd, RawFd},
13 prelude::AsRawFd,
14 },
15};
16
17#[derive(Debug)]
22#[cfg(feature = "libc")]
23pub struct FileDesc<'a> {
24 fd: RawFd,
25 close_on_drop: bool,
26 phantom: PhantomData<&'a ()>,
27}
28
29#[cfg(not(feature = "libc"))]
30pub enum FileDesc<'a> {
31 Owned(OwnedFd),
32 Borrowed(BorrowedFd<'a>),
33}
34
35#[cfg(feature = "libc")]
36impl FileDesc<'_> {
37 pub fn new(fd: RawFd, close_on_drop: bool) -> FileDesc<'static> {
44 FileDesc {
45 fd,
46 close_on_drop,
47 phantom: PhantomData,
48 }
49 }
50
51 pub fn read(&self, buffer: &mut [u8]) -> io::Result<usize> {
52 let result = unsafe {
53 libc::read(
54 self.fd,
55 buffer.as_mut_ptr() as *mut libc::c_void,
56 buffer.len() as size_t,
57 )
58 };
59
60 if result < 0 {
61 Err(io::Error::last_os_error())
62 } else {
63 Ok(result as usize)
64 }
65 }
66
67 pub fn raw_fd(&self) -> RawFd {
69 self.fd
70 }
71}
72
73#[cfg(not(feature = "libc"))]
74impl FileDesc<'_> {
75 pub fn read(&self, buffer: &mut [u8]) -> io::Result<usize> {
76 let fd = match self {
77 FileDesc::Owned(fd) => fd.as_fd(),
78 FileDesc::Borrowed(fd) => fd.as_fd(),
79 };
80 let result = rustix::io::read(fd, buffer)?;
81 Ok(result)
82 }
83
84 pub fn raw_fd(&self) -> RawFd {
85 match self {
86 FileDesc::Owned(fd) => fd.as_raw_fd(),
87 FileDesc::Borrowed(fd) => fd.as_raw_fd(),
88 }
89 }
90}
91
92#[cfg(feature = "libc")]
93impl Drop for FileDesc<'_> {
94 fn drop(&mut self) {
95 if self.close_on_drop {
96 let _ = unsafe { libc::close(self.fd) };
102 }
103 }
104}
105
106impl AsRawFd for FileDesc<'_> {
107 fn as_raw_fd(&self) -> RawFd {
108 self.raw_fd()
109 }
110}
111
112#[cfg(not(feature = "libc"))]
113impl AsFd for FileDesc<'_> {
114 fn as_fd(&self) -> BorrowedFd<'_> {
115 match self {
116 FileDesc::Owned(fd) => fd.as_fd(),
117 FileDesc::Borrowed(fd) => fd.as_fd(),
118 }
119 }
120}
121
122#[cfg(feature = "libc")]
123pub fn tty_fd() -> io::Result<FileDesc<'static>> {
125 let (fd, close_on_drop) = if unsafe { libc::isatty(libc::STDIN_FILENO) == 1 } {
126 (libc::STDIN_FILENO, false)
127 } else {
128 (
129 fs::OpenOptions::new()
130 .read(true)
131 .write(true)
132 .open("/dev/tty")?
133 .into_raw_fd(),
134 true,
135 )
136 };
137
138 Ok(FileDesc::new(fd, close_on_drop))
139}
140
141#[cfg(not(feature = "libc"))]
142pub fn tty_fd() -> io::Result<FileDesc<'static>> {
144 use std::fs::File;
145
146 let stdin = rustix::stdio::stdin();
147 let fd = if rustix::termios::isatty(stdin) {
148 FileDesc::Borrowed(stdin)
149 } else {
150 let dev_tty = File::options().read(true).write(true).open("/dev/tty")?;
151 FileDesc::Owned(dev_tty.into())
152 };
153 Ok(fd)
154}