1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#![allow(clippy::missing_safety_doc)]

use alloc::boxed::Box;
use core::mem::ManuallyDrop;

#[cfg(doc)]
use crate::interfaces::IUnknown;

/// A COM compliant class
///
/// # Safety
///
/// The implementing struct must have the following properties:
/// * it is `#[repr(C)]`
/// * The first fields of the struct are pointers to the backing VTables for
/// each of the COM Interfaces the class implements
pub unsafe trait Class {
    /// The factory object associated with this class
    type Factory;

    /// Decrement the current reference count and return the new count
    ///
    /// # Safety
    ///
    /// Because the caller is directly modifying the reference count of an
    /// object, and reference counts are used to determine object lifetime,
    /// the caller is responsible for ensuring that the object is destroyed
    /// if `dec_ref_count` reaches zero. All such adjustments to the
    /// reference count can only be used by `unsafe` code, because this method
    /// has a side effect (modifies the reference count) but this side effect
    /// is not represented in Rust's type system (no refcount-holding object
    /// is destroyed).
    ///
    /// This method should only be called in [`Drop`] implementations, or similar
    /// functions that terminate the lifetime of a reference-holding type.
    unsafe fn dec_ref_count(&self) -> u32;

    /// Increment the current reference count and return the new count
    ///
    /// # Safety
    ///
    /// Because the caller is directly modifying the reference count of an
    /// object, and reference counts are used to determine object lifetime,
    /// the caller is responsible for ensuring that the newly-created reference
    /// is correctly encapsulated within a Rust object. All such adjustments to
    /// the reference count can only be used by `unsafe` code, because this
    /// method has a side effect (modifies the reference count) but this side
    /// effect is not represented in Rust's type system (no refcount-holding
    /// object is destroyed).
    ///
    /// This method should only be called in type constructors, [`Clone`]
    /// implementations, [`IUnknown::query_interface()`] implementations, or similar
    /// code paths that create a new instance of a Rust type that holds the
    /// counted reference.
    unsafe fn add_ref(&self) -> u32;
}

/// An allocated COM class
///
/// The class must be heap allocated and not be moved in memory.
/// This wrapper decrements the inner class ref count when dropped
/// and frees the heap allocation as well as the class itself when
/// that ref count is 0.
#[repr(transparent)]
pub struct ClassAllocation<T: Class> {
    inner: core::mem::ManuallyDrop<core::pin::Pin<Box<T>>>,
}

impl<T: Class> ClassAllocation<T> {
    /// Create a new class allocation
    ///
    /// This is not normally used by users of the COM crate but by the code generator
    pub fn new(inner: core::pin::Pin<Box<T>>) -> Self {
        Self {
            inner: core::mem::ManuallyDrop::new(inner),
        }
    }

    /// Create an allocated class from a raw pointer
    ///
    /// # Safety
    /// Must be a valid, owned pointer to an allocated COM class. This returns an owned [`ClassAllocation`]
    /// which will drop the wrapped COM class when it is dropped.
    #[inline(always)]
    pub unsafe fn from_raw(raw: *mut T) -> Self {
        let inner = core::mem::ManuallyDrop::new(Box::from_raw(raw).into());
        Self { inner }
    }

    /// Drop (free) the inner allocation.
    ///
    /// This function is never inlined, so that the (relatively) cold path of
    /// freeing an object is kept out of the inlined `Release` call paths.
    #[doc(hidden)]
    #[inline(never)]
    pub unsafe fn drop_inner(&mut self) {
        ManuallyDrop::drop(&mut self.inner);
    }
}

/// [`ClassAllocation<T>`] is [`Send`] because it represents an owned reference to
/// a heap allocation, and the changes to that reference count are atomic.
unsafe impl<T: Class> Send for ClassAllocation<T> {}

/// [`ClassAllocation<T>`] is [`Sync`] because it represents an aliased (shared)
/// reference to a heap-allocated object, and the only way you can gain access
/// to that heap object is to acquire a `&self` (shared) reference.
unsafe impl<T: Class> Sync for ClassAllocation<T> {}

impl<T: Class> core::ops::Deref for ClassAllocation<T> {
    type Target = core::pin::Pin<Box<T>>;

    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl<T: Class> Drop for ClassAllocation<T> {
    fn drop(&mut self) {
        unsafe {
            if self.inner.dec_ref_count() == 0 {
                // SAFETY: This is safe because the inner value is not accessible by anyone else
                core::mem::ManuallyDrop::drop(&mut self.inner);
            }
        }
    }
}

impl<T: Class + core::fmt::Debug> core::fmt::Debug for ClassAllocation<T> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        let inner = self.inner.as_ref().get_ref();
        write!(f, "{:?}", inner)
    }
}

impl<T: Class> Clone for ClassAllocation<T> {
    fn clone(&self) -> Self {
        unsafe {
            self.inner.add_ref();
            core::mem::transmute_copy(self)
        }
    }
}