Skip to content

Commit

Permalink
crate-level documentation for vst3-bindgen and com-scrape-types
Browse files Browse the repository at this point in the history
  • Loading branch information
micahrj committed Jun 12, 2023
1 parent 477ba06 commit bf742b4
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 6 deletions.
2 changes: 1 addition & 1 deletion com-scrape-types/src/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ where
const HEADER: Self::Header;
}

/// Specifies the list of COM interfaces implemented by a Rust type.
/// A Rust type that defines a COM class.
///
/// Must be implemented for a type to be used with [`ComWrapper`].
pub trait Class {
Expand Down
83 changes: 83 additions & 0 deletions com-scrape-types/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,87 @@
//! Support types and traits for bindings generated by `com-scrape`.
//!
//! [`ComPtr`] and [`ComRef`] are smart pointers for interacting with COM objects (calling methods,
//! casting between interfaces, and managing reference counts). The [`Class`] trait can be used for
//! defining COM classes in Rust, and [`ComWrapper`] is a smart pointer used for instantiating
//! those classes.
//!
//! # Reference counting
//!
//! COM objects are reference-counted. The [`ComPtr`] and [`ComRef`] smart pointers manage this
//! automatically where possible, but the function signatures generated by `com-scrape` still pass
//! COM objects as raw pointers, and care must be taken to handle issues of ownership correctly
//! when converting between [`ComPtr`] or [`ComRef`] and raw pointers at these boundaries.
//!
//! A thorough overview of how to manage reference counts for COM objects in a variety of situations
//! can be found on the ["Rules for Managing Reference Counts"][rules] page in the Microsoft COM
//! documentation, and the documentation for each individual [`ComPtr`] and[`ComRef`] method
//! specifies its effect on an object's reference count. However, the following rules of thumb
//! should suffice in the majority of situations:
//!
//! 1. When passing an interface pointer as a function parameter, use [`ComPtr::as_ptr`] to obtain a
//! raw pointer from a [`ComPtr`], or use [`ComRef::as_ptr`] to obtain a raw pointer from a
//! [`ComRef`].
//!
//! 2. When receiving an interface pointer as the return value of a function (or via an out
//! parameter), always use [`ComPtr::from_raw`] to obtain a [`ComPtr`] from the raw pointer.
//!
//! 3. When receiving an interface pointer as a function parameter, always use
//! [`ComRef::from_raw`] to obtain a [`ComRef`] from the raw pointer. If the received interface
//! pointer will be stored beyond the duration of the current function, use
//! [`ComRef::to_com_ptr`] to upgrade the [`ComRef`] to a [`ComPtr`].
//!
//! 4. When returning an interface pointer from a function (or when returning it via an out
//! parameter), always use [`ComPtr::into_raw`] to obtain a raw pointer from a [`ComPtr`].
//!
//! [rules]: https://learn.microsoft.com/en-us/windows/win32/com/rules-for-managing-reference-counts
//!
//! # Implementing COM interfaces from Rust
//!
//! The [`Class`] trait can be used to define COM classes in Rust, and the [`ComWrapper`] smart
//! pointer can be used to instantiate objects of these classes. To define a COM class, start by
//! defining a Rust type:
//!
//! ```ignore
//! struct MyClass { /* ... */ }
//! ```
//!
//! Then implement the desired interface traits for the type:
//!
//! ```ignore
//! impl ISomeInterfaceTrait for MyClass {
//! unsafe fn some_method(&self) {
//! /* ... */
//! }
//! }
//!
//! impl IAnotherInterfaceTrait for MyClass {
//! unsafe fn another_method(&self) {
//! /* ... */
//! }
//! }
//! ```
//!
//! Finally, implement the [`Class`] trait for the type, specifying the set of COM interfaces as a
//! tuple:
//!
//! ```ignore
//! impl Class for MyClass {
//! type Interfaces = (ISomeInterface, IAnotherInterface);
//! }
//! ```
//!
//! With these definitions in place, [`ComWrapper`] can be used to instantiate a COM object
//! supporting the above interfaces:
//!
//! ```ignore
//! let my_obj = ComWrapper::new(MyClass);
//!
//! let ptr = my_obj.to_com_ptr::<ISomeInterface>().unwrap();
//! ptr.some_method();
//!
//! let ptr = my_obj.to_com_ptr::<IAnotherInterface>().unwrap();
//! ptr.another_method();
//! ```
mod class;
mod ptr;
Expand Down
12 changes: 7 additions & 5 deletions com-scrape-types/src/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ pub trait SmartPtr {
/// A non-owning smart pointer to a COM object.
///
/// A `ComRef<'a, I>` represents a borrowed reference to a COM object implementing interface `I`.
/// Like [`ComPtr`], `ComRef` can be used to call interface methods on the referenced object, but
/// unlike `ComPtr`, `ComRef` does not manage the object's reference count, i.e. it will *not* call
/// the object's release method when going out of scope.
/// Like [`ComPtr`], `ComRef` can be used to call interface methods on the referenced object.
/// Unlike [`ComPtr`], `ComRef` does not manage the object's reference count, i.e. it will *not*
/// call the release method of the object it points to when going out of scope. See the
/// [crate-level documentation](crate#reference-counting) for more information.
///
/// A `ComRef` can be created safely from a [`ComPtr`] via [`ComPtr::as_com_ref`], or from a
/// [`ComWrapper`][crate::ComWrapper] via [`ComWrapper::as_com_ref`][crate::ComWrapper::as_com_ref].
Expand Down Expand Up @@ -160,8 +161,9 @@ impl<'a, I: Interface> ComRef<'a, I> {
///
/// A `ComPtr<I>` represents an owning reference to a COM object implementing interface `I`. Like
/// [`ComRef`], `ComPtr` can be used to call interface methods on the referenced object. Unlike
/// [`ComRef`], `ComPtr` does perform reference counting operations, i.e. it *will* call the
/// release method of the object it points to when going out of scope.
/// [`ComRef`], `ComPtr` manages the object's reference count, i.e. it *will* call the release
/// method of the object it points to when going out of scope. See the
/// [crate-level documentation](crate#reference-counting) for more information.
///
/// A `ComPtr` can be created safely from a [`ComRef`] via [`ComRef::to_com_ptr`], or from a
/// [`ComWrapper`][crate::ComWrapper] via [`ComWrapper::to_com_ptr`][crate::ComWrapper::to_com_ptr].
Expand Down
59 changes: 59 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,62 @@
//! `vst3-bindgen` provides Rust bindings for the VST 3 API, generated from the original C++
//! headers. Abstractions are provided for manipulating COM objects and implementing COM interfaces
//! from Rust. Beyond that, however, these bindings are unsafe, and no attempt is made to abstract
//! over the VST 3 API itself.
//!
//! # Bindings
//!
//! Generated bindings are located in the [`Steinberg`] module. In addition to the COM interfaces,
//! bindings include struct definitions, type aliases, constants, and enums. The module structure
//! of the bindings mirrors the namespace structure of the original headers, with minor differences
//! where necessary (e.g., definitions which are nested inside a C++ type `SomeType` will be found
//! inside a `SomeType_` module in the generated bindings).
//!
//! For each COM interface `IInterface` in the C++ headers, the bindings include a corresponding
//! Rust type `IInterface`, a virtual table struct `IInterfaceVtbl`, and a trait `IInterfaceTrait`
//! (excluding `FUnknown`, for which no trait is generated). Each `IInterface` type also implements
//! the [`Interface`] trait, which holds an associated constant [`Interface::IID`] specifying the
//! GUID corresponding to that interface.
//!
//! # Interacting with COM objects
//!
//! The [`ComPtr`] and [`ComRef`] smart pointers are provided for interacting with COM objects.
//! These types make it safer and more convenient to call methods, cast between interfaces, and
//! manage reference counts.
//!
//! For an overview of how to properly manage ownership and reference counts using [`ComPtr`] and
//! [`ComRef`], see the [`com-scrape-types` documentation](com_scrape_types#reference-counting).
//!
//! # Implementing COM interfaces from Rust
//!
//! COM classes can be defined in Rust using the [`Class`] trait and the interface traits generated
//! by `vst3-bindgen`, and objects of these classes can be instantiated using the
//! [`ComWrapper`] smart pointer:
//!
//! ```
//! # use vst3_bindgen::{*, Steinberg::*};
//! struct MyClass;
//!
//! impl Class for MyClass {
//! type Interfaces = (IPluginBase,);
//! }
//!
//! impl IPluginBaseTrait for MyClass {
//! unsafe fn initialize(&self, context: *mut FUnknown) -> tresult {
//! kResultOk
//! }
//!
//! unsafe fn terminate(&self) -> tresult {
//! kResultOk
//! }
//! }
//!
//! let my_obj = ComWrapper::new(MyClass);
//! let ptr = my_obj.to_com_ptr::<IPluginBase>().unwrap();
//! ```
//!
//! For more detail on implementing COM interfaces from rust, see the
//! [`com-scrape-types` documentation](com_scrape_types#implementing-com-interfaces-from-rust).
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
Expand Down

0 comments on commit bf742b4

Please sign in to comment.