1use crate::{AsRaw, Device, DeviceDestroyedError, Format, Modifier, Ptr, WeakPtr};
2
3#[cfg(feature = "drm-support")]
4use drm::buffer::{Buffer as DrmBuffer, Handle, PlanarBuffer as DrmPlanarBuffer};
5use std::os::unix::io::{AsFd, FromRawFd, OwnedFd};
6
7use std::error;
8use std::fmt;
9use std::io::{Error as IoError, Result as IoResult};
10use std::marker::PhantomData;
11use std::ops::{Deref, DerefMut};
12use std::ptr;
13use std::slice;
14
15/// A GBM buffer object
16pub struct BufferObject<T: 'static> {
17 pub(crate) ffi: Ptr<ffi::gbm_bo>,
18 pub(crate) _device: WeakPtr<ffi::gbm_device>,
19 pub(crate) _userdata: PhantomData<T>,
20}
21
22impl<T> fmt::Debug for BufferObject<T> {
23 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24 f&mut DebugStruct<'_, '_>.debug_struct("BufferObject")
25 .field("ptr", &format_args!("{:p}", self.ffi))
26 .field("device", &format_args!("{:p}", &self._device))
27 .field("width", &self.width().unwrap_or(0))
28 .field("height", &self.height().unwrap_or(0))
29 .field("offsets", &self.offsets())
30 .field("stride", &self.stride().unwrap_or(0))
31 .field("format", &self.format().ok())
32 .field(name:"modifier", &self.modifier().ok())
33 .finish()
34 }
35}
36
37bitflags! {
38 /// Flags to indicate the intended use for the buffer - these are passed into
39 /// [`Device::create_buffer_object()`].
40 ///
41 /// Use [`Device::is_format_supported()`] to check if the combination of format
42 /// and use flags are supported
43 pub struct BufferObjectFlags: u32 {
44 /// Buffer is going to be presented to the screen using an API such as KMS
45 const SCANOUT = ffi::gbm_bo_flags::GBM_BO_USE_SCANOUT as u32;
46 /// Buffer is going to be used as cursor
47 const CURSOR = ffi::gbm_bo_flags::GBM_BO_USE_CURSOR as u32;
48 /// Buffer is going to be used as cursor (deprecated)
49 #[deprecated = "Use CURSOR instead"]
50 const CURSOR_64X64 = ffi::gbm_bo_flags::GBM_BO_USE_CURSOR_64X64 as u32;
51 /// Buffer is to be used for rendering - for example it is going to be used
52 /// as the storage for a color buffer
53 const RENDERING = ffi::gbm_bo_flags::GBM_BO_USE_RENDERING as u32;
54 /// Buffer can be used for [`BufferObject::write()`]. This is guaranteed to work
55 /// with [`Self::CURSOR`], but may not work for other combinations.
56 const WRITE = ffi::gbm_bo_flags::GBM_BO_USE_WRITE as u32;
57 /// Buffer is linear, i.e. not tiled.
58 const LINEAR = ffi::gbm_bo_flags::GBM_BO_USE_LINEAR as u32;
59 /// Buffer is protected
60 const PROTECTED = ffi::gbm_bo_flags::GBM_BO_USE_PROTECTED as u32;
61 }
62}
63
64/// Abstraction representing the handle to a buffer allocated by the manager
65pub type BufferObjectHandle = ffi::gbm_bo_handle;
66
67enum BORef<'a, T: 'static> {
68 Ref(&'a BufferObject<T>),
69 Mut(&'a mut BufferObject<T>),
70}
71
72/// A mapped buffer object
73pub struct MappedBufferObject<'a, T: 'static> {
74 bo: BORef<'a, T>,
75 buffer: &'a mut [u8],
76 data: *mut ::libc::c_void,
77 stride: u32,
78 height: u32,
79 width: u32,
80 x: u32,
81 y: u32,
82}
83
84impl<'a, T> fmt::Debug for MappedBufferObject<'a, T> {
85 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
86 f&mut DebugStruct<'_, '_>.debug_struct("MappedBufferObject")
87 .field(
88 "mode",
89 &match self.bo {
90 BORef::Ref(_) => format_args!("read"),
91 BORef::Mut(_) => format_args!("write"),
92 },
93 )
94 .field(
95 name:"buffer",
96 value:match &self.bo {
97 BORef::Ref(bo: &&BufferObject) => *bo,
98 BORef::Mut(bo: &&mut BufferObject) => *bo,
99 },
100 )
101 .finish()
102 }
103}
104
105impl<'a, T: 'static> MappedBufferObject<'a, T> {
106 /// Get the stride of the buffer object
107 ///
108 /// This is calculated by the backend when it does the allocation of the buffer.
109 pub fn stride(&self) -> u32 {
110 self.stride
111 }
112
113 /// The height of the mapped region for the buffer
114 pub fn height(&self) -> u32 {
115 self.height
116 }
117
118 /// The width of the mapped region for the buffer
119 pub fn width(&self) -> u32 {
120 self.width
121 }
122
123 /// The X (top left origin) starting position of the mapped region for the buffer
124 pub fn x(&self) -> u32 {
125 self.x
126 }
127
128 /// The Y (top left origin) starting position of the mapped region for the buffer
129 pub fn y(&self) -> u32 {
130 self.y
131 }
132
133 /// Access to the underlying image buffer
134 pub fn buffer(&self) -> &[u8] {
135 self.buffer
136 }
137
138 /// Mutable access to the underlying image buffer
139 pub fn buffer_mut(&mut self) -> &mut [u8] {
140 self.buffer
141 }
142}
143
144impl<'a, T: 'static> Deref for MappedBufferObject<'a, T> {
145 type Target = BufferObject<T>;
146 fn deref(&self) -> &BufferObject<T> {
147 match &self.bo {
148 BORef::Ref(bo: &&BufferObject) => bo,
149 BORef::Mut(bo: &&mut BufferObject) => bo,
150 }
151 }
152}
153
154impl<'a, T: 'static> DerefMut for MappedBufferObject<'a, T> {
155 fn deref_mut(&mut self) -> &mut BufferObject<T> {
156 match &mut self.bo {
157 BORef::Ref(_) => unreachable!(),
158 BORef::Mut(bo: &mut &mut BufferObject) => bo,
159 }
160 }
161}
162
163impl<'a, T: 'static> Drop for MappedBufferObject<'a, T> {
164 fn drop(&mut self) {
165 let ffi: &Ptr<{unknown}> = match &self.bo {
166 BORef::Ref(bo: &&BufferObject) => &bo.ffi,
167 BORef::Mut(bo: &&mut BufferObject) => &bo.ffi,
168 };
169 unsafe { ffi::gbm_bo_unmap(**ffi, self.data) }
170 }
171}
172
173unsafe extern "C" fn destroy<T: 'static>(_: *mut ffi::gbm_bo, ptr: *mut ::libc::c_void) {
174 let ptr: *mut T = ptr as *mut T;
175 if !ptr.is_null() {
176 let _ = Box::from_raw(ptr);
177 }
178}
179
180impl<T: 'static> BufferObject<T> {
181 /// Get the width of the buffer object
182 pub fn width(&self) -> Result<u32, DeviceDestroyedError> {
183 self._device.upgrade().ok_or(DeviceDestroyedError)?;
184 Ok(unsafe { ffi::gbm_bo_get_width(*self.ffi) })
185 }
186
187 /// Get the height of the buffer object
188 pub fn height(&self) -> Result<u32, DeviceDestroyedError> {
189 self._device.upgrade().ok_or(DeviceDestroyedError)?;
190 Ok(unsafe { ffi::gbm_bo_get_height(*self.ffi) })
191 }
192
193 /// Get the stride of the buffer object
194 pub fn stride(&self) -> Result<u32, DeviceDestroyedError> {
195 self._device.upgrade().ok_or(DeviceDestroyedError)?;
196 Ok(unsafe { ffi::gbm_bo_get_stride(*self.ffi) })
197 }
198
199 /// Get the stride of the buffer object
200 pub fn stride_for_plane(&self, plane: i32) -> Result<u32, DeviceDestroyedError> {
201 self._device.upgrade().ok_or(DeviceDestroyedError)?;
202 Ok(unsafe { ffi::gbm_bo_get_stride_for_plane(*self.ffi, plane) })
203 }
204
205 /// Get the format of the buffer object
206 pub fn format(&self) -> Result<Format, DeviceDestroyedError> {
207 self._device.upgrade().ok_or(DeviceDestroyedError)?;
208 Ok(
209 Format::try_from(unsafe { ffi::gbm_bo_get_format(*self.ffi) })
210 .expect("libgbm returned invalid buffer format"),
211 )
212 }
213
214 /// Get the bits per pixel of the buffer object
215 pub fn bpp(&self) -> Result<u32, DeviceDestroyedError> {
216 self._device.upgrade().ok_or(DeviceDestroyedError)?;
217 Ok(unsafe { ffi::gbm_bo_get_bpp(*self.ffi) })
218 }
219
220 /// Get the offset for a plane of the buffer object
221 pub fn offset(&self, plane: i32) -> Result<u32, DeviceDestroyedError> {
222 self._device.upgrade().ok_or(DeviceDestroyedError)?;
223 Ok(unsafe { ffi::gbm_bo_get_offset(*self.ffi, plane) })
224 }
225
226 /// Get the plane count of the buffer object
227 pub fn plane_count(&self) -> Result<u32, DeviceDestroyedError> {
228 self._device.upgrade().ok_or(DeviceDestroyedError)?;
229 Ok(unsafe { ffi::gbm_bo_get_plane_count(*self.ffi) as u32 })
230 }
231
232 /// Get the modifier of the buffer object
233 pub fn modifier(&self) -> Result<Modifier, DeviceDestroyedError> {
234 self._device.upgrade().ok_or(DeviceDestroyedError)?;
235 Ok(Modifier::from(unsafe {
236 ffi::gbm_bo_get_modifier(*self.ffi)
237 }))
238 }
239
240 /// Get a DMA-BUF file descriptor for the buffer object
241 ///
242 /// This function creates a DMA-BUF (also known as PRIME) file descriptor
243 /// handle for the buffer object. Each call to [`Self::fd()`] returns a new
244 /// file descriptor and the caller is responsible for closing the file
245 /// descriptor.
246 pub fn fd(&self) -> Result<OwnedFd, FdError> {
247 self._device.upgrade().ok_or(DeviceDestroyedError)?;
248 unsafe {
249 let fd = ffi::gbm_bo_get_fd(*self.ffi);
250
251 if fd == -1 {
252 return Err(InvalidFdError.into());
253 }
254
255 Ok(OwnedFd::from_raw_fd(fd))
256 }
257 }
258
259 /// Get the handle of the buffer object
260 ///
261 /// This is stored in the platform generic union [`BufferObjectHandle`] type. However
262 /// the format of this handle is platform specific.
263 pub fn handle(&self) -> Result<BufferObjectHandle, DeviceDestroyedError> {
264 self._device.upgrade().ok_or(DeviceDestroyedError)?;
265 Ok(unsafe { ffi::gbm_bo_get_handle(*self.ffi) })
266 }
267
268 /// Get a DMA-BUF file descriptor for a plane of the buffer object
269 ///
270 /// This function creates a DMA-BUF (also known as PRIME) file descriptor
271 /// handle for a plane of the buffer object. Each call to [`Self::fd_for_plane()`]
272 /// returns a new file descriptor and the caller is responsible for closing
273 /// the file descriptor.
274 pub fn fd_for_plane(&self, plane: i32) -> Result<OwnedFd, FdError> {
275 self._device.upgrade().ok_or(DeviceDestroyedError)?;
276 unsafe {
277 let fd = ffi::gbm_bo_get_fd_for_plane(*self.ffi, plane);
278
279 if fd == -1 {
280 return Err(InvalidFdError.into());
281 }
282
283 Ok(OwnedFd::from_raw_fd(fd))
284 }
285 }
286
287 /// Get the handle of a plane of the buffer object
288 ///
289 /// This is stored in the platform generic union [`BufferObjectHandle`] type. However
290 /// the format of this handle is platform specific.
291 pub fn handle_for_plane(&self, plane: i32) -> Result<BufferObjectHandle, DeviceDestroyedError> {
292 self._device.upgrade().ok_or(DeviceDestroyedError)?;
293 Ok(unsafe { ffi::gbm_bo_get_handle_for_plane(*self.ffi, plane) })
294 }
295
296 /// Map a region of a GBM buffer object for cpu access
297 ///
298 /// This function maps a region of a GBM bo for cpu read access.
299 pub fn map<'a, D, F, S>(
300 &'a self,
301 device: &Device<D>,
302 x: u32,
303 y: u32,
304 width: u32,
305 height: u32,
306 f: F,
307 ) -> Result<IoResult<S>, WrongDeviceError>
308 where
309 D: AsFd + 'static,
310 F: FnOnce(&MappedBufferObject<'a, T>) -> S,
311 {
312 let device_ref = self._device.upgrade().ok_or(WrongDeviceError)?;
313 if *device_ref != device.as_raw_mut() {
314 // not matching
315 return Err(WrongDeviceError);
316 }
317
318 unsafe {
319 let mut data: *mut ::libc::c_void = ptr::null_mut();
320 let mut stride = 0;
321 let ptr = ffi::gbm_bo_map(
322 *self.ffi,
323 x,
324 y,
325 width,
326 height,
327 ffi::gbm_bo_transfer_flags::GBM_BO_TRANSFER_READ as u32,
328 &mut stride as *mut _,
329 &mut data as *mut _,
330 );
331
332 if ptr.is_null() {
333 Ok(Err(IoError::last_os_error()))
334 } else {
335 Ok(Ok(f(&MappedBufferObject {
336 bo: BORef::Ref(self),
337 buffer: slice::from_raw_parts_mut(ptr as *mut _, (height * stride) as usize),
338 data,
339 stride,
340 height,
341 width,
342 x,
343 y,
344 })))
345 }
346 }
347 }
348
349 /// Map a region of a GBM buffer object for cpu access
350 ///
351 /// This function maps a region of a GBM bo for cpu read/write access.
352 pub fn map_mut<'a, D, F, S>(
353 &'a mut self,
354 device: &Device<D>,
355 x: u32,
356 y: u32,
357 width: u32,
358 height: u32,
359 f: F,
360 ) -> Result<IoResult<S>, WrongDeviceError>
361 where
362 D: AsFd + 'static,
363 F: FnOnce(&mut MappedBufferObject<'a, T>) -> S,
364 {
365 let device_ref = self._device.upgrade().ok_or(WrongDeviceError)?;
366 if *device_ref != device.as_raw_mut() {
367 // not matching
368 return Err(WrongDeviceError);
369 }
370
371 unsafe {
372 let mut data: *mut ::libc::c_void = ptr::null_mut();
373 let mut stride = 0;
374 let ptr = ffi::gbm_bo_map(
375 *self.ffi,
376 x,
377 y,
378 width,
379 height,
380 ffi::gbm_bo_transfer_flags::GBM_BO_TRANSFER_READ_WRITE as u32,
381 &mut stride as *mut _,
382 &mut data as *mut _,
383 );
384
385 if ptr.is_null() {
386 Ok(Err(IoError::last_os_error()))
387 } else {
388 Ok(Ok(f(&mut MappedBufferObject {
389 bo: BORef::Mut(self),
390 buffer: slice::from_raw_parts_mut(ptr as *mut _, (height * stride) as usize),
391 data,
392 stride,
393 height,
394 width,
395 x,
396 y,
397 })))
398 }
399 }
400 }
401
402 /// Write data into the buffer object
403 ///
404 /// If the buffer object was created with the [`BufferObjectFlags::WRITE`] flag,
405 /// this function can be used to write data into the buffer object. The
406 /// data is copied directly into the object and it's the responsibility
407 /// of the caller to make sure the data represents valid pixel data,
408 /// according to the width, height, stride and format of the buffer object.
409 pub fn write(&mut self, buffer: &[u8]) -> Result<IoResult<()>, DeviceDestroyedError> {
410 self._device.upgrade().ok_or(DeviceDestroyedError)?;
411 let result =
412 unsafe { ffi::gbm_bo_write(*self.ffi, buffer.as_ptr() as *const _, buffer.len() as _) };
413 if result != 0 {
414 Ok(Err(IoError::last_os_error()))
415 } else {
416 Ok(Ok(()))
417 }
418 }
419
420 /// Sets the userdata of the buffer object.
421 ///
422 /// If previously userdata was set, it is returned.
423 pub fn set_userdata(&mut self, userdata: T) -> Result<Option<T>, DeviceDestroyedError> {
424 self._device.upgrade().ok_or(DeviceDestroyedError)?;
425 let old = self.take_userdata();
426
427 let boxed = Box::new(userdata);
428 unsafe {
429 ffi::gbm_bo_set_user_data(
430 *self.ffi,
431 Box::into_raw(boxed) as *mut _,
432 Some(destroy::<T>),
433 );
434 }
435
436 old
437 }
438
439 /// Clears the set userdata of the buffer object.
440 pub fn clear_userdata(&mut self) -> Result<(), DeviceDestroyedError> {
441 self._device.upgrade().ok_or(DeviceDestroyedError)?;
442 let _ = self.take_userdata();
443 Ok(())
444 }
445
446 /// Returns a reference to set userdata, if any.
447 pub fn userdata(&self) -> Result<Option<&T>, DeviceDestroyedError> {
448 self._device.upgrade().ok_or(DeviceDestroyedError)?;
449 let raw = unsafe { ffi::gbm_bo_get_user_data(*self.ffi) };
450
451 if raw.is_null() {
452 Ok(None)
453 } else {
454 unsafe { Ok(Some(&*(raw as *mut T))) }
455 }
456 }
457
458 /// Returns a mutable reference to set userdata, if any.
459 pub fn userdata_mut(&mut self) -> Result<Option<&mut T>, DeviceDestroyedError> {
460 self._device.upgrade().ok_or(DeviceDestroyedError)?;
461 let raw = unsafe { ffi::gbm_bo_get_user_data(*self.ffi) };
462
463 if raw.is_null() {
464 Ok(None)
465 } else {
466 unsafe { Ok(Some(&mut *(raw as *mut T))) }
467 }
468 }
469
470 /// Takes ownership of previously set userdata, if any.
471 ///
472 /// This removes the userdata from the buffer object.
473 pub fn take_userdata(&mut self) -> Result<Option<T>, DeviceDestroyedError> {
474 self._device.upgrade().ok_or(DeviceDestroyedError)?;
475 let raw = unsafe { ffi::gbm_bo_get_user_data(*self.ffi) };
476
477 if raw.is_null() {
478 Ok(None)
479 } else {
480 unsafe {
481 let boxed = Box::from_raw(raw as *mut T);
482 ffi::gbm_bo_set_user_data(*self.ffi, ptr::null_mut(), None);
483 Ok(Some(*boxed))
484 }
485 }
486 }
487
488 pub(crate) unsafe fn new(
489 ffi: *mut ffi::gbm_bo,
490 device: WeakPtr<ffi::gbm_device>,
491 ) -> BufferObject<T> {
492 BufferObject {
493 ffi: Ptr::<ffi::gbm_bo>::new(ffi, |ptr| ffi::gbm_bo_destroy(ptr)),
494 _device: device,
495 _userdata: PhantomData,
496 }
497 }
498}
499
500impl<T: 'static> AsRaw<ffi::gbm_bo> for BufferObject<T> {
501 fn as_raw(&self) -> *const ffi::gbm_bo {
502 *self.ffi
503 }
504}
505
506#[cfg(feature = "drm-support")]
507impl<T: 'static> DrmBuffer for BufferObject<T> {
508 fn size(&self) -> (u32, u32) {
509 (
510 self.width().expect("GbmDevice does not exist anymore"),
511 self.height().expect("GbmDevice does not exist anymore"),
512 )
513 }
514
515 fn format(&self) -> Format {
516 BufferObject::<T>::format(self).expect("GbmDevice does not exist anymore")
517 }
518
519 fn pitch(&self) -> u32 {
520 self.stride().expect("GbmDevice does not exist anymore")
521 }
522
523 fn handle(&self) -> Handle {
524 use std::num::NonZeroU32;
525 unsafe {
526 Handle::from(NonZeroU32::new_unchecked(
527 self.handle()
528 .expect("GbmDevice does not exist anymore")
529 .u32_,
530 ))
531 }
532 }
533}
534
535#[cfg(feature = "drm-support")]
536impl<T: 'static> DrmPlanarBuffer for BufferObject<T> {
537 fn size(&self) -> (u32, u32) {
538 (
539 self.width().expect("GbmDevice does not exist anymore"),
540 self.height().expect("GbmDevice does not exist anymore"),
541 )
542 }
543 fn format(&self) -> Format {
544 BufferObject::<T>::format(self).expect("GbmDevice does not exist anymore")
545 }
546 fn pitches(&self) -> [u32; 4] {
547 let num = self
548 .plane_count()
549 .expect("GbmDevice does not exist anymore");
550 [
551 BufferObject::<T>::stride_for_plane(self, 0).unwrap(),
552 if num > 1 {
553 BufferObject::<T>::stride_for_plane(self, 1).unwrap()
554 } else {
555 0
556 },
557 if num > 2 {
558 BufferObject::<T>::stride_for_plane(self, 2).unwrap()
559 } else {
560 0
561 },
562 if num > 3 {
563 BufferObject::<T>::stride_for_plane(self, 3).unwrap()
564 } else {
565 0
566 },
567 ]
568 }
569 fn handles(&self) -> [Option<Handle>; 4] {
570 use std::num::NonZeroU32;
571 let num = self
572 .plane_count()
573 .expect("GbmDevice does not exist anymore");
574 [
575 Some(unsafe {
576 Handle::from(NonZeroU32::new_unchecked(
577 BufferObject::<T>::handle_for_plane(self, 0).unwrap().u32_,
578 ))
579 }),
580 if num > 1 {
581 Some(unsafe {
582 Handle::from(NonZeroU32::new_unchecked(
583 BufferObject::<T>::handle_for_plane(self, 1).unwrap().u32_,
584 ))
585 })
586 } else {
587 None
588 },
589 if num > 2 {
590 Some(unsafe {
591 Handle::from(NonZeroU32::new_unchecked(
592 BufferObject::<T>::handle_for_plane(self, 2).unwrap().u32_,
593 ))
594 })
595 } else {
596 None
597 },
598 if num > 3 {
599 Some(unsafe {
600 Handle::from(NonZeroU32::new_unchecked(
601 BufferObject::<T>::handle_for_plane(self, 3).unwrap().u32_,
602 ))
603 })
604 } else {
605 None
606 },
607 ]
608 }
609 fn offsets(&self) -> [u32; 4] {
610 let num = self
611 .plane_count()
612 .expect("GbmDevice does not exist anymore");
613 [
614 BufferObject::<T>::offset(self, 0).unwrap(),
615 if num > 1 {
616 BufferObject::<T>::offset(self, 1).unwrap()
617 } else {
618 0
619 },
620 if num > 2 {
621 BufferObject::<T>::offset(self, 2).unwrap()
622 } else {
623 0
624 },
625 if num > 3 {
626 BufferObject::<T>::offset(self, 3).unwrap()
627 } else {
628 0
629 },
630 ]
631 }
632}
633
634#[derive(Debug, Clone, Copy, PartialEq, Eq)]
635/// Thrown when the GBM device does not belong to the buffer object
636pub struct WrongDeviceError;
637
638impl fmt::Display for WrongDeviceError {
639 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
640 write!(
641 f,
642 "The gbm device specified is not the one this buffer object belongs to"
643 )
644 }
645}
646
647impl error::Error for WrongDeviceError {}
648
649/// Thrown when the fd is invalid
650#[derive(Debug, Clone, Copy, PartialEq, Eq)]
651pub struct InvalidFdError;
652
653impl fmt::Display for InvalidFdError {
654 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
655 write!(f, "The returned fd is invalid")
656 }
657}
658
659impl error::Error for InvalidFdError {}
660
661/// Thrown when an error occurs during getting a bo fd
662#[derive(Debug, Clone, Copy, PartialEq, Eq)]
663pub enum FdError {
664 /// The underlying device has been destroyed
665 DeviceDestroyed(DeviceDestroyedError),
666 /// The operation returned an invalid fd
667 InvalidFd(InvalidFdError),
668}
669
670impl From<DeviceDestroyedError> for FdError {
671 fn from(err: DeviceDestroyedError) -> Self {
672 FdError::DeviceDestroyed(err)
673 }
674}
675
676impl From<InvalidFdError> for FdError {
677 fn from(err: InvalidFdError) -> Self {
678 FdError::InvalidFd(err)
679 }
680}
681
682impl fmt::Display for FdError {
683 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
684 match self {
685 FdError::DeviceDestroyed(err: &DeviceDestroyedError) => err.fmt(f),
686 FdError::InvalidFd(err: &InvalidFdError) => err.fmt(f),
687 }
688 }
689}
690
691impl error::Error for FdError {
692 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
693 match self {
694 FdError::DeviceDestroyed(err: &DeviceDestroyedError) => Some(err),
695 FdError::InvalidFd(err: &InvalidFdError) => Some(err),
696 }
697 }
698}
699