vst3 0.3.0

Rust bindings for the VST 3 API
Documentation
use std::ffi::c_void;

use com_scrape_types::{Class, Construct, Guid, Header, InterfaceList, Wrapper};

use crate::Steinberg::{int8, tresult, uint32, FUnknown, FUnknownVtbl, TUID};

pub const fn tuid_as_guid(tuid: TUID) -> Guid {
    [
        tuid[0] as u8,
        tuid[1] as u8,
        tuid[2] as u8,
        tuid[3] as u8,
        tuid[4] as u8,
        tuid[5] as u8,
        tuid[6] as u8,
        tuid[7] as u8,
        tuid[8] as u8,
        tuid[9] as u8,
        tuid[10] as u8,
        tuid[11] as u8,
        tuid[12] as u8,
        tuid[13] as u8,
        tuid[14] as u8,
        tuid[15] as u8,
    ]
}

#[inline]
pub unsafe fn FUnknown_query_interface(this: *mut c_void, iid: &Guid) -> Option<*mut c_void> {
    let ptr = this as *mut FUnknown;
    let mut obj = std::ptr::null_mut();
    let result = ((*(*ptr).vtbl).queryInterface)(ptr, iid.as_ptr() as *const TUID, &mut obj);

    if result == kResultOk {
        Some(obj)
    } else {
        None
    }
}

#[inline]
pub unsafe fn FUnknown_add_ref(this: *mut c_void) -> usize {
    let ptr = this as *mut FUnknown;
    ((*(*ptr).vtbl).addRef)(ptr) as usize
}

#[inline]
pub unsafe fn FUnknown_release(this: *mut c_void) -> usize {
    let ptr = this as *mut FUnknown;
    ((*(*ptr).vtbl).release)(ptr) as usize
}

impl FUnknown {
    pub const fn make_vtbl<C, W, const OFFSET: isize>() -> FUnknownVtbl
    where
        C: Class,
        W: Wrapper<C>,
    {
        unsafe extern "system" fn queryInterface<C, W, const OFFSET: isize>(
            this: *mut FUnknown,
            _iid: *const TUID,
            obj: *mut *mut c_void,
        ) -> tresult
        where
            C: Class,
            W: Wrapper<C>,
        {
            let header_ptr = (this as *mut u8).offset(-OFFSET) as *mut Header<C>;
            if let Some(result) = C::Interfaces::query(&*(_iid as *const Guid)) {
                let ptr = W::data_from_header(header_ptr);
                W::add_ref(ptr);

                std::ptr::write_unaligned(
                    obj,
                    (header_ptr as *mut u8).offset(result) as *mut c_void,
                );

                kResultOk
            } else {
                kNoInterface
            }
        }

        unsafe extern "system" fn addRef<C, W, const OFFSET: isize>(this: *mut FUnknown) -> uint32
        where
            C: Class,
            W: Wrapper<C>,
        {
            let header_ptr = (this as *mut u8).offset(-OFFSET) as *mut Header<C>;
            let ptr = W::data_from_header(header_ptr);
            W::add_ref(ptr) as uint32
        }

        unsafe extern "system" fn release<C, W, const OFFSET: isize>(this: *mut FUnknown) -> uint32
        where
            C: Class,
            W: Wrapper<C>,
        {
            let header_ptr = (this as *mut u8).offset(-OFFSET) as *mut Header<C>;
            let ptr = W::data_from_header(header_ptr);
            W::release(ptr) as uint32
        }

        FUnknownVtbl {
            queryInterface: queryInterface::<C, W, OFFSET>,
            addRef: addRef::<C, W, OFFSET>,
            release: release::<C, W, OFFSET>,
        }
    }
}

unsafe impl<C, W, const OFFSET: isize> Construct<C, W, OFFSET> for FUnknown
where
    C: Class,
    W: Wrapper<C>,
{
    const OBJ: FUnknown = FUnknown {
        vtbl: &Self::make_vtbl::<C, W, OFFSET>(),
    };
}

/// Constructs a 16-byte [`TUID`] value from four 32-bit integers.
///
/// Note that the byte order of the resulting value will differ between Windows and other
/// platforms.
pub const fn uid(a: u32, b: u32, c: u32, d: u32) -> TUID {
    uid_impl(a, b, c, d)
}

#[cfg(target_os = "windows")]
const fn uid_impl(a: u32, b: u32, c: u32, d: u32) -> TUID {
    [
        ((a & 0x000000FF) >> 0) as int8,
        ((a & 0x0000FF00) >> 8) as int8,
        ((a & 0x00FF0000) >> 16) as int8,
        ((a & 0xFF000000) >> 24) as int8,
        ((b & 0x00FF0000) >> 16) as int8,
        ((b & 0xFF000000) >> 24) as int8,
        ((b & 0x000000FF) >> 0) as int8,
        ((b & 0x0000FF00) >> 8) as int8,
        ((c & 0xFF000000) >> 24) as int8,
        ((c & 0x00FF0000) >> 16) as int8,
        ((c & 0x0000FF00) >> 8) as int8,
        ((c & 0x000000FF) >> 0) as int8,
        ((d & 0xFF000000) >> 24) as int8,
        ((d & 0x00FF0000) >> 16) as int8,
        ((d & 0x0000FF00) >> 8) as int8,
        ((d & 0x000000FF) >> 0) as int8,
    ]
}

#[cfg(not(target_os = "windows"))]
const fn uid_impl(a: u32, b: u32, c: u32, d: u32) -> TUID {
    [
        ((a & 0xFF000000) >> 24) as int8,
        ((a & 0x00FF0000) >> 16) as int8,
        ((a & 0x0000FF00) >> 8) as int8,
        ((a & 0x000000FF) >> 0) as int8,
        ((b & 0xFF000000) >> 24) as int8,
        ((b & 0x00FF0000) >> 16) as int8,
        ((b & 0x0000FF00) >> 8) as int8,
        ((b & 0x000000FF) >> 0) as int8,
        ((c & 0xFF000000) >> 24) as int8,
        ((c & 0x00FF0000) >> 16) as int8,
        ((c & 0x0000FF00) >> 8) as int8,
        ((c & 0x000000FF) >> 0) as int8,
        ((d & 0xFF000000) >> 24) as int8,
        ((d & 0x00FF0000) >> 16) as int8,
        ((d & 0x0000FF00) >> 8) as int8,
        ((d & 0x000000FF) >> 0) as int8,
    ]
}

#[cfg(target_os = "windows")]
mod result_values {
    #![allow(overflowing_literals)]

    use std::ffi::c_int;

    pub const kNoInterface: c_int = 0x80004002;
    pub const kResultOk: c_int = 0x00000000;
    pub const kResultTrue: c_int = kResultOk;
    pub const kResultFalse: c_int = 0x00000001;
    pub const kInvalidArgument: c_int = 0x80070057;
    pub const kNotImplemented: c_int = 0x80004001;
    pub const kInternalError: c_int = 0x80004005;
    pub const kNotInitialized: c_int = 0x8000FFFF;
    pub const kOutOfMemory: c_int = 0x8007000E;
}

#[cfg(not(target_os = "windows"))]
mod result_values {
    use std::ffi::c_int;

    pub const kNoInterface: c_int = -1;
    pub const kResultOk: c_int = 0;
    pub const kResultTrue: c_int = kResultOk;
    pub const kResultFalse: c_int = 1;
    pub const kInvalidArgument: c_int = 2;
    pub const kNotImplemented: c_int = 3;
    pub const kInternalError: c_int = 4;
    pub const kNotInitialized: c_int = 5;
    pub const kOutOfMemory: c_int = 6;
}

pub use result_values::*;

#[cfg(target_os = "windows")]
pub type DefaultEnumType = std::ffi::c_int;

#[cfg(not(target_os = "windows"))]
pub type DefaultEnumType = std::ffi::c_uint;