diff --git a/gio/src/desktop_app_info.rs b/gio/src/desktop_app_info.rs index f849c99b0dbc..6592989058a2 100644 --- a/gio/src/desktop_app_info.rs +++ b/gio/src/desktop_app_info.rs @@ -3,7 +3,7 @@ #[cfg(all(unix, feature = "v2_58"))] use std::boxed::Box as Box_; #[cfg(all(unix, feature = "v2_58"))] -use std::os::unix::io::AsRawFd; +use std::os::unix::io::{AsFd, AsRawFd}; #[cfg(all(unix, feature = "v2_58"))] use std::ptr; @@ -48,21 +48,16 @@ impl DesktopAppInfo { pub trait DesktopAppInfoExtManual: IsA { #[cfg_attr(docsrs, doc(cfg(all(feature = "v2_58", unix))))] #[doc(alias = "g_desktop_app_info_launch_uris_as_manager_with_fds")] - fn launch_uris_as_manager_with_fds< - P: IsA, - T: AsRawFd, - U: AsRawFd, - V: AsRawFd, - >( + fn launch_uris_as_manager_with_fds>( &self, uris: &[&str], launch_context: Option<&P>, spawn_flags: glib::SpawnFlags, user_setup: Option>, pid_callback: Option<&mut dyn (FnMut(&DesktopAppInfo, glib::Pid))>, - stdin_fd: &mut T, - stdout_fd: &mut U, - stderr_fd: &mut V, + stdin_fd: Option, + stdout_fd: Option, + stderr_fd: Option, ) -> Result<(), Error> { let user_setup_data: Box_>> = Box_::new(user_setup); unsafe extern "C" fn user_setup_func(user_data: glib::ffi::gpointer) { @@ -99,6 +94,10 @@ pub trait DesktopAppInfoExtManual: IsA { let super_callback0: Box_>> = user_setup_data; let super_callback1: &Option<&mut dyn (FnMut(&DesktopAppInfo, glib::Pid))> = &pid_callback_data; + + let stdin_raw_fd = stdin_fd.map_or(-1, |fd| fd.as_fd().as_raw_fd()); + let stdout_raw_fd = stdout_fd.map_or(-1, |fd| fd.as_fd().as_raw_fd()); + let stderr_raw_fd = stderr_fd.map_or(-1, |fd| fd.as_fd().as_raw_fd()); unsafe { let mut error = ptr::null_mut(); let _ = ffi::g_desktop_app_info_launch_uris_as_manager_with_fds( @@ -110,9 +109,9 @@ pub trait DesktopAppInfoExtManual: IsA { Box_::into_raw(super_callback0) as *mut _, pid_callback, super_callback1 as *const _ as *mut _, - stdin_fd.as_raw_fd(), - stdout_fd.as_raw_fd(), - stderr_fd.as_raw_fd(), + stdin_raw_fd, + stdout_raw_fd, + stderr_raw_fd, &mut error, ); if error.is_null() { diff --git a/gio/src/socket.rs b/gio/src/socket.rs index 507e3ff6f58a..da27490d8499 100644 --- a/gio/src/socket.rs +++ b/gio/src/socket.rs @@ -1,7 +1,7 @@ // Take a look at the license at the top of the repository in the LICENSE file. #[cfg(unix)] -use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; #[cfg(windows)] use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket}; #[cfg(feature = "v2_60")] @@ -18,15 +18,18 @@ use crate::{ffi, Cancellable, Socket, SocketAddress, SocketControlMessage}; impl Socket { #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] - #[allow(clippy::missing_safety_doc)] - pub unsafe fn from_fd(fd: impl IntoRawFd) -> Result { + #[doc(alias = "g_socket_new_from_fd")] + pub fn from_fd(fd: OwnedFd) -> Result { let fd = fd.into_raw_fd(); let mut error = ptr::null_mut(); - let ret = ffi::g_socket_new_from_fd(fd, &mut error); - if error.is_null() { - Ok(from_glib_full(ret)) - } else { - Err(from_glib_full(error)) + unsafe { + let ret = ffi::g_socket_new_from_fd(fd, &mut error); + if error.is_null() { + Ok(from_glib_full(ret)) + } else { + libc::close(fd); + Err(from_glib_full(error)) + } } } #[cfg(windows)] @@ -52,6 +55,17 @@ impl AsRawFd for Socket { } } +#[cfg(unix)] +#[cfg_attr(docsrs, doc(cfg(unix)))] +impl AsFd for Socket { + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { + let raw_fd = self.as_raw_fd(); + BorrowedFd::borrow_raw(raw_fd) + } + } +} + #[cfg(windows)] #[cfg_attr(docsrs, doc(cfg(windows)))] impl AsRawSocket for Socket { @@ -801,7 +815,10 @@ mod tests { #[test] #[cfg(unix)] fn socket_messages() { - use std::{io, os::unix::io::AsRawFd}; + use std::{ + io, + os::unix::io::{AsRawFd, FromRawFd, OwnedFd}, + }; use super::Socket; use crate::{prelude::*, Cancellable, UnixFDMessage}; @@ -813,8 +830,8 @@ mod tests { panic!("{}", io::Error::last_os_error()); } ( - Socket::from_fd(fds[0]).unwrap(), - Socket::from_fd(fds[1]).unwrap(), + Socket::from_fd(OwnedFd::from_raw_fd(fds[0])).unwrap(), + Socket::from_fd(OwnedFd::from_raw_fd(fds[1])).unwrap(), ) }; diff --git a/gio/src/unix_input_stream.rs b/gio/src/unix_input_stream.rs index 479951cee6eb..a1f3e8769a8b 100644 --- a/gio/src/unix_input_stream.rs +++ b/gio/src/unix_input_stream.rs @@ -1,27 +1,24 @@ // Take a look at the license at the top of the repository in the LICENSE file. #[cfg(unix)] -use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; +use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, IntoRawFd, OwnedFd, RawFd}; use glib::{prelude::*, translate::*}; #[cfg(all(not(unix), docsrs))] -use socket::{AsRawFd, IntoRawFd, RawFd}; +use socket::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::{ffi, InputStream, UnixInputStream}; impl UnixInputStream { // rustdoc-stripper-ignore-next /// Creates a new [`Self`] that takes ownership of the passed in fd. - /// - /// # Safety - /// You must not close the fd unless you've previously called [`UnixInputStreamExtManual::set_close_fd`] - /// with `true` on this stream. At which point you may only do so when all references to this - /// stream have been dropped. #[doc(alias = "g_unix_input_stream_new")] - pub unsafe fn take_fd(fd: impl IntoRawFd) -> UnixInputStream { + pub fn take_fd(fd: OwnedFd) -> UnixInputStream { let fd = fd.into_raw_fd(); let close_fd = true.into_glib(); - InputStream::from_glib_full(ffi::g_unix_input_stream_new(fd, close_fd)).unsafe_cast() + unsafe { + InputStream::from_glib_full(ffi::g_unix_input_stream_new(fd, close_fd)).unsafe_cast() + } } // rustdoc-stripper-ignore-next @@ -43,6 +40,15 @@ impl AsRawFd for UnixInputStream { } } +impl AsFd for UnixInputStream { + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { + let raw_fd = self.as_raw_fd(); + BorrowedFd::borrow_raw(raw_fd) + } + } +} + pub trait UnixInputStreamExtManual: IsA + Sized { // rustdoc-stripper-ignore-next /// Sets whether the fd of this stream will be closed when the stream is closed. diff --git a/gio/src/unix_output_stream.rs b/gio/src/unix_output_stream.rs index 3fbfdab713f4..acd30a22f510 100644 --- a/gio/src/unix_output_stream.rs +++ b/gio/src/unix_output_stream.rs @@ -1,27 +1,24 @@ // Take a look at the license at the top of the repository in the LICENSE file. #[cfg(unix)] -use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; +use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, IntoRawFd, OwnedFd, RawFd}; use glib::{prelude::*, translate::*}; #[cfg(all(not(unix), docsrs))] -use socket::{AsRawFd, IntoRawFd, RawFd}; +use socket::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::{ffi, OutputStream, UnixOutputStream}; impl UnixOutputStream { // rustdoc-stripper-ignore-next /// Creates a new [`Self`] that takes ownership of the passed in fd. - /// - /// # Safety - /// You must not close the fd unless you've previously called [`UnixOutputStreamExtManual::set_close_fd`] - /// on this stream. At which point you may only do so when all references to this stream have - /// been dropped. #[doc(alias = "g_unix_output_stream_new")] - pub unsafe fn take_fd(fd: impl IntoRawFd) -> UnixOutputStream { + pub fn take_fd(fd: OwnedFd) -> UnixOutputStream { let fd = fd.into_raw_fd(); let close_fd = true.into_glib(); - OutputStream::from_glib_full(ffi::g_unix_output_stream_new(fd, close_fd)).unsafe_cast() + unsafe { + OutputStream::from_glib_full(ffi::g_unix_output_stream_new(fd, close_fd)).unsafe_cast() + } } // rustdoc-stripper-ignore-next @@ -43,6 +40,15 @@ impl AsRawFd for UnixOutputStream { } } +impl AsFd for UnixOutputStream { + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { + let raw_fd = self.as_raw_fd(); + BorrowedFd::borrow_raw(raw_fd) + } + } +} + pub trait UnixOutputStreamExtManual: IsA + Sized { // rustdoc-stripper-ignore-next /// Sets whether the fd of this stream will be closed when the stream is closed. diff --git a/gio/tests/dbus_peer.rs b/gio/tests/dbus_peer.rs index 1df590eb5626..1cfb07586c78 100644 --- a/gio/tests/dbus_peer.rs +++ b/gio/tests/dbus_peer.rs @@ -8,7 +8,7 @@ fn test_gdbus_peer_connection() { prelude::*, DBusConnection, DBusConnectionFlags, DBusNodeInfo, Socket, }; - use std::os::{fd::IntoRawFd, unix::net::UnixStream}; + use std::os::unix::net::UnixStream; const EXAMPLE_XML: &str = r#" @@ -23,7 +23,7 @@ fn test_gdbus_peer_connection() { "#; pub async fn spawn_server(fd: UnixStream) -> DBusConnection { - let socket = unsafe { Socket::from_fd(fd.into_raw_fd()) }.unwrap(); + let socket = Socket::from_fd(fd.into()).unwrap(); let socket_connection = socket.connection_factory_create_connection(); let guid = gio::dbus_generate_guid(); @@ -112,7 +112,7 @@ fn test_gdbus_peer_connection() { } pub async fn spawn_client(fd: UnixStream) -> DBusConnection { - let socket_client = unsafe { Socket::from_fd(fd.into_raw_fd()) }.unwrap(); + let socket_client = Socket::from_fd(fd.into()).unwrap(); let socket_connection_client = socket_client.connection_factory_create_connection(); dbg!("client connecting"); diff --git a/glib/src/functions.rs b/glib/src/functions.rs index 708a7d4cad08..851467740bbe 100644 --- a/glib/src/functions.rs +++ b/glib/src/functions.rs @@ -7,7 +7,7 @@ use std::boxed::Box as Box_; use std::mem; #[cfg(not(windows))] #[cfg(feature = "v2_58")] -use std::os::unix::io::AsRawFd; +use std::os::unix::io::{AsFd, AsRawFd}; #[cfg(not(windows))] use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd}; use std::ptr; @@ -24,15 +24,15 @@ use crate::{Error, Pid, SpawnFlags}; #[cfg_attr(docsrs, doc(cfg(all(feature = "v2_58", not(windows)))))] #[allow(clippy::too_many_arguments)] #[doc(alias = "g_spawn_async_with_fds")] -pub fn spawn_async_with_fds, T: AsRawFd, U: AsRawFd, V: AsRawFd>( +pub fn spawn_async_with_fds>( working_directory: P, argv: &[&str], envp: &[&str], flags: SpawnFlags, child_setup: Option>, - stdin_fd: T, - stdout_fd: U, - stderr_fd: V, + stdin_fd: Option, + stdout_fd: Option, + stderr_fd: Option, ) -> Result { let child_setup_data: Box_>> = Box_::new(child_setup); unsafe extern "C" fn child_setup_func(user_data: ffi::gpointer) { @@ -47,6 +47,9 @@ pub fn spawn_async_with_fds, T: AsRawFd, U: AsRawFd, V None }; let super_callback0: Box_>> = child_setup_data; + let stdin_raw_fd = stdin_fd.map_or(-1, |fd| fd.as_fd().as_raw_fd()); + let stdout_raw_fd = stdout_fd.map_or(-1, |fd| fd.as_fd().as_raw_fd()); + let stderr_raw_fd = stderr_fd.map_or(-1, |fd| fd.as_fd().as_raw_fd()); unsafe { let mut child_pid = mem::MaybeUninit::uninit(); let mut error = ptr::null_mut(); @@ -58,9 +61,9 @@ pub fn spawn_async_with_fds, T: AsRawFd, U: AsRawFd, V child_setup, Box_::into_raw(super_callback0) as *mut _, child_pid.as_mut_ptr(), - stdin_fd.as_raw_fd(), - stdout_fd.as_raw_fd(), - stderr_fd.as_raw_fd(), + stdin_raw_fd, + stdout_raw_fd, + stderr_raw_fd, &mut error, ); let child_pid = from_glib(child_pid.assume_init()); diff --git a/glib/src/log.rs b/glib/src/log.rs index d4a7471989bf..6b30dd85ff4a 100644 --- a/glib/src/log.rs +++ b/glib/src/log.rs @@ -1,7 +1,7 @@ // Take a look at the license at the top of the repository in the LICENSE file. #[cfg(unix)] -use std::os::unix::io::AsRawFd; +use std::os::unix::io::{AsFd, AsRawFd}; use std::{ boxed::Box as Box_, sync::{Arc, Mutex, OnceLock}, @@ -972,16 +972,20 @@ pub fn log_variant(log_domain: Option<&str>, log_level: LogLevel, fields: &crate #[cfg_attr(docsrs, doc(cfg(unix)))] #[doc(alias = "g_log_writer_supports_color")] #[inline] -pub fn log_writer_supports_color(output_fd: T) -> bool { - unsafe { from_glib(ffi::g_log_writer_supports_color(output_fd.as_raw_fd())) } +pub fn log_writer_supports_color(output_fd: impl AsFd) -> bool { + unsafe { + from_glib(ffi::g_log_writer_supports_color( + output_fd.as_fd().as_raw_fd(), + )) + } } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] #[doc(alias = "g_log_writer_is_journald")] #[inline] -pub fn log_writer_is_journald(output_fd: T) -> bool { - unsafe { from_glib(ffi::g_log_writer_is_journald(output_fd.as_raw_fd())) } +pub fn log_writer_is_journald(output_fd: impl AsFd) -> bool { + unsafe { from_glib(ffi::g_log_writer_is_journald(output_fd.as_fd().as_raw_fd())) } } #[doc(alias = "g_log_writer_format_fields")]