Skip to content

Commit

Permalink
move generator into separate vst3-bindgen crate
Browse files Browse the repository at this point in the history
  • Loading branch information
glowcoil committed Aug 7, 2023
1 parent eb3d442 commit 50d69c1
Show file tree
Hide file tree
Showing 11 changed files with 326 additions and 274 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

## 0.1.0

- Initial release.
- Split up `vst3-bindgen` crate. `vst3-bindgen` is now a library which `vst3` uses from `build.rs`.
7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[package]
name = "vst3"
version = "0.1.1"
version = "0.1.0"
authors = ["Micah Johnston <[email protected]>"]
edition = "2021"
description = "Binding generator for the VST 3 API"
description = "Rust bindings for the VST 3 API"
documentation = "https://coupler.rs/vst3-rs/vst3/"
repository = "https://github.com/coupler-rs/vst3-rs"
license = "MIT OR Apache-2.0"
Expand All @@ -12,7 +12,7 @@ license = "MIT OR Apache-2.0"
com-scrape-types = { path = "com-scrape-types", version = "0.1.0" }

[build-dependencies]
com-scrape = { path = "com-scrape", version = "0.1.1" }
vst3-bindgen = { path = "vst3-bindgen", version = "0.2.0" }

[[example]]
name = "gain"
Expand All @@ -22,4 +22,5 @@ crate-type = ["cdylib"]
members = [
"com-scrape",
"com-scrape-types",
"vst3-bindgen",
]
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ First, add `vst3` as a dependency to your `Cargo.toml`:

```toml
[dependencies]
vst3 = "0.1.1"
vst3 = "0.1.0"
```

Then, download the VST 3 SDK:
Expand Down
99 changes: 8 additions & 91 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,98 +1,10 @@
use std::collections::HashSet;
use std::env;
use std::error::Error;
use std::fs::File;
use std::io::BufWriter;
use std::path::{Path, PathBuf};
use std::path::Path;
use std::process;
use std::{fs, io};

fn find_headers<P: AsRef<Path>>(dir: P) -> Result<Vec<PathBuf>, io::Error> {
fn find_headers_inner<P: AsRef<Path>>(dir: P, headers: &mut Vec<PathBuf>) -> io::Result<()> {
for entry in fs::read_dir(dir)? {
let entry = entry?;
let metadata = entry.metadata()?;

let path = entry.path();
if metadata.file_type().is_dir() {
find_headers_inner(path, headers)?;
} else {
if path.extension().map(|ext| ext == "h").unwrap_or(false) {
headers.push(path);
}
}
}

Ok(())
}

let mut headers = Vec::new();
find_headers_inner(dir, &mut headers)?;

Ok(headers)
}

fn parse_iid(tokens: &[String]) -> Option<String> {
if let Some(first) = tokens.first() {
if first == "DECLARE_CLASS_IID" {
return Some(format!(
"pub const {}_iid: TUID = uid({}, {}, {}, {});",
tokens[2], tokens[4], tokens[6], tokens[8], tokens[10]
));
}
}

None
}

fn generate(sdk_dir: &str) -> Result<(), Box<dyn Error>> {
let pluginterfaces_path = Path::new(&sdk_dir).join("pluginterfaces");
let headers = find_headers(&pluginterfaces_path)?;

let skip_headers = HashSet::from([
Path::new("pluginterfaces/base/funknownimpl.h"),
Path::new("pluginterfaces/base/ustring.h"),
Path::new("pluginterfaces/test/itest.h"),
Path::new("pluginterfaces/vst/ivsttestplugprovider.h"),
]);

let mut source = String::new();
for header in &headers {
let relative = header.strip_prefix(&sdk_dir).unwrap();
if skip_headers.contains(relative) {
continue;
}

let name = relative.to_str().unwrap();

use std::fmt::Write;
writeln!(source, "#include \"{}\"", name)?;
}

let out_dir = env::var("OUT_DIR").unwrap();

let bindings = File::create(Path::new(&out_dir).join("bindings.rs"))?;
let sink = BufWriter::new(bindings);

com_scrape::Generator::default()
.skip_types(&[
"Adopt",
"ConstStringTable",
"FUID",
"FReleaser",
"LARGE_INT",
])
.skip_interface_trait("FUnknown")
.constant_parser(parse_iid)
.iid_generator(|name| format!("crate::tuid_as_guid({name}_iid)"))
.query_interface_fn("crate::FUnknown_query_interface")
.add_ref_fn("crate::FUnknown_add_ref")
.release_fn("crate::FUnknown_release")
.include_path(&sdk_dir)
.generate(source, sink)?;

Ok(())
}
use vst3_bindgen::generate;

fn main() {
println!("cargo:rerun-if-env-changed=VST3_SDK_DIR");
Expand All @@ -105,7 +17,12 @@ fn main() {

println!("cargo:rerun-if-changed={}", vst3_sdk_dir);

if let Err(err) = generate(&vst3_sdk_dir) {
let out_dir = env::var("OUT_DIR").unwrap();

let bindings = File::create(Path::new(&out_dir).join("bindings.rs")).unwrap();
let sink = BufWriter::new(bindings);

if let Err(err) = generate(Path::new(&vst3_sdk_dir), sink) {
eprintln!("{}", err);
process::exit(1);
}
Expand Down
3 changes: 2 additions & 1 deletion com-scrape/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

## 0.1.1

- Update `com-scrape` version to 0.1.1.
- Check for and report Clang errors when parsing C++ headers.
- Fix generation failures when using Clang from Xcode command line tools.

## 0.1.0

Expand Down
177 changes: 0 additions & 177 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,181 +57,4 @@
//! 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)]

use std::ffi::c_void;

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

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

pub use com_scrape_types;
pub use com_scrape_types::{Class, ComPtr, ComRef, ComWrapper, Interface};

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]
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]
unsafe fn FUnknown_add_ref(this: *mut c_void) -> usize {
let ptr = this as *mut FUnknown;
((*(*ptr).vtbl).addRef)(ptr) as usize
}

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

impl FUnknown {
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);

*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,
]
}

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
13 changes: 13 additions & 0 deletions vst3-bindgen/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Changelog

## 0.2.0

- Split up `vst3-bindgen` crate. `vst3-bindgen` is now a library which `vst3` uses from `build.rs`.

## 0.1.1

- Update `com-scrape` version to 0.1.1.

## 0.1.0

- Initial release.
11 changes: 11 additions & 0 deletions vst3-bindgen/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "vst3-bindgen"
version = "0.2.0"
authors = ["Micah Johnston <[email protected]>"]
edition = "2021"
description = "Binding generator for the VST 3 API"
repository = "https://github.com/coupler-rs/vst3-rs"
license = "MIT OR Apache-2.0"

[dependencies]
com-scrape = { path = "../com-scrape", version = "0.1.1" }
10 changes: 10 additions & 0 deletions vst3-bindgen/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# vst3-bindgen

[![Cargo](https://img.shields.io/crates/v/vst3-bindgen.svg)](https://crates.io/crates/vst3-bindgen)
[![Docs](https://docs.rs/vst3-bindgen/badge.svg)](https://docs.rs/vst3-bindgen)

A binding generator for the VST 3 API. `vst3-bindgen` can be used to generate Rust bindings for the VST 3 API from the original C++ headers.

## License

`vst3-bindgen` is distributed under the terms of both the [MIT license](LICENSE-MIT) and the [Apache license, version 2.0](LICENSE-APACHE). Contributions are accepted under the same terms.
Loading

0 comments on commit 50d69c1

Please sign in to comment.