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}