diff --git a/gio/src/unix_fd_list.rs b/gio/src/unix_fd_list.rs index 49b649c80ed3..ac2e56d87b6d 100644 --- a/gio/src/unix_fd_list.rs +++ b/gio/src/unix_fd_list.rs @@ -1,12 +1,12 @@ // Take a look at the license at the top of the repository in the LICENSE file. #[cfg(unix)] -use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; +use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd}; use std::{mem, ptr}; use glib::{prelude::*, translate::*}; #[cfg(all(not(unix), docsrs))] -use socket::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; +use socket::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd}; use crate::{ffi, UnixFDList}; @@ -74,16 +74,79 @@ pub trait UnixFDListExtManual: sealed::Sealed + IsA + Sized { } #[doc(alias = "g_unix_fd_list_steal_fds")] - fn steal_fds(&self) -> Vec { + fn steal_fds(&self) -> FdArray { unsafe { let mut length = mem::MaybeUninit::uninit(); - let ret: Vec = FromGlibContainer::from_glib_full_num( - ffi::g_unix_fd_list_steal_fds(self.as_ref().to_glib_none().0, length.as_mut_ptr()), - length.assume_init() as usize, - ); - ret.into_iter().map(|fd| OwnedFd::from_raw_fd(fd)).collect() + + let ptr = + ffi::g_unix_fd_list_steal_fds(self.as_ref().to_glib_none().0, length.as_mut_ptr()); + + FdArray { + ptr: ptr::NonNull::new(ptr).unwrap(), + len: length.assume_init() as usize, + } } } } impl> UnixFDListExtManual for O {} + +pub struct FdArray { + ptr: ptr::NonNull, + len: usize, +} + +pub struct FdIterator { + ptr: ptr::NonNull, + len: usize, +} + +impl Iterator for FdIterator { + type Item = OwnedFd; + + fn next(&mut self) -> Option { + if self.len > 0 { + let current = self.ptr.as_ptr(); + if self.len > 1 { + let next = unsafe { self.ptr.as_ptr().add(1) }; + self.ptr = ptr::NonNull::new(next).unwrap(); + } + self.len -= 1; + Some(unsafe { OwnedFd::from_raw_fd(*current) }) + } else { + None + } + } +} + +impl Drop for FdArray { + fn drop(&mut self) { + while self.len > 0 { + unsafe { + let current = self.ptr.as_ptr(); + libc::close(*current); + } + if self.len > 1 { + let next = unsafe { self.ptr.as_ptr().add(1) }; + self.ptr = ptr::NonNull::new(next).unwrap(); + } + self.len -= 1; + } + } +} + +impl std::iter::IntoIterator for FdArray { + type Item = OwnedFd; + type IntoIter = FdIterator; + + fn into_iter(mut self) -> Self::IntoIter { + let len = std::mem::take(&mut self.len); + FdIterator { len, ptr: self.ptr } + } +} + +impl FdArray { + pub fn as_slice(&self) -> &[BorrowedFd<'_>] { + unsafe { std::slice::from_raw_parts(self.ptr.as_ptr() as *const BorrowedFd, self.len) } + } +}