rutabaga_gfx/rutabaga_os/
descriptor.rs

1// Copyright 2022 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::fs::File;
6use std::mem;
7use std::mem::ManuallyDrop;
8
9use crate::rutabaga_os::RawDescriptor;
10
11/// Wraps a RawDescriptor and safely closes it when self falls out of scope.
12pub struct SafeDescriptor {
13    pub(crate) descriptor: RawDescriptor,
14}
15
16/// Trait for forfeiting ownership of the current raw descriptor, and returning the raw descriptor
17pub trait IntoRawDescriptor {
18    fn into_raw_descriptor(self) -> RawDescriptor;
19}
20
21/// Trait for returning the underlying raw descriptor, without giving up ownership of the
22/// descriptor.
23pub trait AsRawDescriptor {
24    /// Returns the underlying raw descriptor.
25    ///
26    /// Since the descriptor is still owned by the provider, callers should not assume that it will
27    /// remain open for longer than the immediate call of this method. In particular, it is a
28    /// dangerous practice to store the result of this method for future use: instead, it should be
29    /// used to e.g. obtain a raw descriptor that is immediately passed to a system call.
30    ///
31    /// If you need to use the descriptor for a longer time (and particularly if you cannot reliably
32    /// track the lifetime of the providing object), you should probably consider using
33    /// [`SafeDescriptor`] (possibly along with [`trait@IntoRawDescriptor`]) to get full ownership
34    /// over a descriptor pointing to the same resource.
35    fn as_raw_descriptor(&self) -> RawDescriptor;
36}
37
38/// A trait similar to `AsRawDescriptor` but supports an arbitrary number of descriptors.
39pub trait AsRawDescriptors {
40    /// Returns the underlying raw descriptors.
41    ///
42    /// Please refer to the documentation of [`AsRawDescriptor::as_raw_descriptor`] for limitations
43    /// and recommended use.
44    fn as_raw_descriptors(&self) -> Vec<RawDescriptor>;
45}
46
47pub trait FromRawDescriptor {
48    /// # Safety
49    /// Safe only if the caller ensures nothing has access to the descriptor after passing it to
50    /// `from_raw_descriptor`
51    unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self;
52}
53
54impl AsRawDescriptor for SafeDescriptor {
55    fn as_raw_descriptor(&self) -> RawDescriptor {
56        self.descriptor
57    }
58}
59
60impl<T> AsRawDescriptors for T
61where
62    T: AsRawDescriptor,
63{
64    fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
65        vec![self.as_raw_descriptor()]
66    }
67}
68
69impl IntoRawDescriptor for SafeDescriptor {
70    fn into_raw_descriptor(self) -> RawDescriptor {
71        let descriptor = self.descriptor;
72        mem::forget(self);
73        descriptor
74    }
75}
76
77impl FromRawDescriptor for SafeDescriptor {
78    /// # Safety
79    /// Safe only if the caller ensures nothing has access to the descriptor after passing it to
80    /// `from_raw_descriptor`
81    unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {
82        SafeDescriptor { descriptor }
83    }
84}
85
86impl TryFrom<&dyn AsRawDescriptor> for SafeDescriptor {
87    type Error = std::io::Error;
88
89    /// Clones the underlying descriptor (handle), internally creating a new descriptor.
90    ///
91    /// WARNING: Windows does NOT support cloning/duplicating all types of handles. DO NOT use this
92    /// function on IO completion ports, sockets, or pseudo-handles (except those from
93    /// GetCurrentProcess or GetCurrentThread). See
94    /// <https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-duplicatehandle>
95    /// for further details.
96    ///
97    /// TODO(b/191800567): this API has sharp edges on Windows. We should evaluate making some
98    /// adjustments to smooth those edges.
99    fn try_from(rd: &dyn AsRawDescriptor) -> std::result::Result<Self, Self::Error> {
100        // SAFETY:
101        // Safe because the underlying raw descriptor is guaranteed valid by rd's existence.
102        //
103        // Note that we are cloning the underlying raw descriptor since we have no guarantee of
104        // its existence after this function returns.
105        let rd_as_safe_desc = ManuallyDrop::new(unsafe {
106            SafeDescriptor::from_raw_descriptor(rd.as_raw_descriptor())
107        });
108
109        // We have to clone rd because we have no guarantee ownership was transferred (rd is
110        // borrowed).
111        rd_as_safe_desc
112            .try_clone()
113            .map_err(|_| Self::Error::last_os_error())
114    }
115}
116
117impl From<File> for SafeDescriptor {
118    fn from(f: File) -> SafeDescriptor {
119        // SAFETY:
120        // Safe because we own the File at this point.
121        unsafe { SafeDescriptor::from_raw_descriptor(f.into_raw_descriptor()) }
122    }
123}
124
125/// For use cases where a simple wrapper around a [`RawDescriptor`] is needed, in order to e.g.
126/// implement [`trait@AsRawDescriptor`].
127///
128/// This is a simply a wrapper and does not manage the lifetime of the descriptor. As such it is the
129/// responsibility of the user to ensure that the wrapped descriptor will not be closed for as long
130/// as the `Descriptor` is alive.
131///
132/// Most use-cases should prefer [`SafeDescriptor`] or implementing and using
133/// [`trait@AsRawDescriptor`] on the type providing the descriptor. Using this wrapper usually means
134/// something can be improved in your code.
135///
136/// Valid uses of this struct include:
137/// * You only have a valid [`RawDescriptor`] and need to pass something that implements
138///   [`trait@AsRawDescriptor`] to a function,
139/// * You need to serialize a [`RawDescriptor`],
140/// * You need [`trait@Send`] or [`trait@Sync`] for your descriptor and properly handle the case
141///   where your descriptor gets closed.
142///
143/// Note that with the exception of the last use-case (which requires proper error checking against
144/// the descriptor being closed), the `Descriptor` instance would be very short-lived.
145#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
146#[repr(transparent)]
147pub struct Descriptor(pub RawDescriptor);
148impl AsRawDescriptor for Descriptor {
149    fn as_raw_descriptor(&self) -> RawDescriptor {
150        self.0
151    }
152}