-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Generate with 19.5.716 - Add parameter tag API - Re-export bindings as ffi::raw - Other missing APIs - Add HAPI_GetOutputNodeId - Get/Set cache properties API --------- Co-authored-by: Aleksei Rusev <hou.alexx@gmail.com>
- Loading branch information
Showing
29 changed files
with
1,559 additions
and
142 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
[package] | ||
name = "coverage" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
regex-lite = "0.1.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
#![allow(dead_code, unused)] | ||
use regex_lite::{Regex, RegexBuilder}; | ||
use std::collections::HashSet; | ||
use std::hash::{Hash, Hasher}; | ||
use std::path::Path; | ||
|
||
fn raw_hapi_function_names() -> HashSet<Item> { | ||
const IGNORE_SUFFIX: &[&str] = &[ | ||
"_IsString", | ||
"_IsFloat", | ||
"_IsInt", | ||
"_AreEqual", | ||
"_IsPath", | ||
"_IsNode", | ||
"_Create", | ||
"_Init", | ||
]; | ||
let raw = Path::new("../../src/ffi/bindings.rs"); | ||
let text = std::fs::read_to_string(&raw).expect("bindings.rs"); | ||
let rx = regex_lite::Regex::new(r#"pub fn (HAPI\w+)\("#).unwrap(); | ||
let matches: HashSet<_> = rx | ||
.captures_iter(&text) | ||
.filter_map(|m| { | ||
let name = &m[1]; | ||
let skip = IGNORE_SUFFIX.iter().any(|suf| name.ends_with(suf)); | ||
if skip { | ||
None | ||
} else { | ||
Some(Item(name.to_string())) | ||
} | ||
}) | ||
.collect(); | ||
matches | ||
} | ||
|
||
#[derive(Debug, Eq)] | ||
struct Item(String); | ||
|
||
impl PartialEq for Item { | ||
fn eq(&self, other: &Item) -> bool { | ||
self.0.to_lowercase() == other.0.to_lowercase() | ||
} | ||
} | ||
|
||
impl Hash for Item { | ||
fn hash<H: Hasher>(&self, hasher: &mut H) { | ||
self.0.to_lowercase().hash(hasher) | ||
} | ||
} | ||
|
||
fn wrapped_rs_function_names() -> HashSet<Item> { | ||
let rx1 = Regex::new(r#"raw::(HAPI\w+)\(?"#).unwrap(); | ||
let rx2 = Regex::new(r#"\[(HAPI\w+)\]"#).unwrap(); | ||
let rx3 = Regex::new(r#".*raw::(HAPI\w+)\("#).unwrap(); | ||
|
||
let text = std::fs::read_to_string("../../src/ffi/functions.rs").expect("functions.rs"); | ||
let it1 = rx1.captures_iter(&text).map(|c| Item(c[1].to_string())); | ||
|
||
let text = std::fs::read_to_string("../../src/attribute/bindings.rs").expect("functions.rs"); | ||
let it2 = rx2.captures_iter(&text).map(|c| Item(c[1].to_string())); | ||
|
||
let it3 = rx3.captures_iter(&text).map(|c| Item(c[1].to_string())); | ||
HashSet::from_iter(it1.chain(it2).chain(it3)) | ||
} | ||
|
||
fn main() { | ||
let raw = raw_hapi_function_names(); | ||
let rs = wrapped_rs_function_names(); | ||
for r in raw.iter() { | ||
if !rs.contains(r) { | ||
println!("Missing {r:?}"); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
[package] | ||
name = "hapi-bindgen" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
heck = "0.4.1" | ||
bindgen = "0.66.1" | ||
once_cell = "1.18.0" | ||
argh = "0.1.10" | ||
anyhow = "1.0.71" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,234 @@ | ||
#![allow(dead_code)] | ||
#![allow(unused)] | ||
|
||
use anyhow::Context; | ||
use argh::FromArgs; | ||
use std::cell::RefCell; | ||
use std::collections::HashMap; | ||
use std::env::var; | ||
use std::path::{Path, PathBuf}; | ||
|
||
use bindgen::callbacks::{EnumVariantValue, ParseCallbacks}; | ||
use once_cell::sync::Lazy; | ||
|
||
#[derive(Debug, Copy, Clone)] | ||
pub enum StripMode { | ||
/// Strip N items at front, e.g N=1: FOO_BAR_ZOO => BAR_ZOO | ||
StripFront(u8), | ||
/// Keeps N items at tail, e.g N=1: FOO_BAR_ZOO => ZOO | ||
KeepTail(u8), | ||
} | ||
|
||
impl StripMode { | ||
pub fn new(m: i32) -> Self { | ||
if m < 0 { | ||
StripMode::KeepTail(m.abs() as u8) | ||
} else { | ||
StripMode::StripFront(m as u8) | ||
} | ||
} | ||
|
||
pub fn strip_long_name<'a>(&self, name: &'a str) -> &'a str { | ||
let mut iter = name.match_indices('_'); | ||
let elem = match self { | ||
StripMode::KeepTail(i) => iter.nth_back((i - 1) as usize), | ||
StripMode::StripFront(i) => iter.nth((i - 1) as usize), | ||
}; | ||
let new_name = match elem { | ||
Some((idx, _)) => &name[idx + 1..name.len()], | ||
None => { | ||
eprintln!("{} Not enough length: {}", line!(), name); | ||
name | ||
} | ||
}; | ||
match new_name.chars().take(1).next() { | ||
None => { | ||
eprintln!("{} Empty string {}", line!(), name); | ||
name | ||
} | ||
// If after first pass the name starts with a digit (illegal name) do another pass | ||
Some(c) if c.is_digit(10) => match self { | ||
StripMode::StripFront(v) => StripMode::StripFront(v + 1), | ||
StripMode::KeepTail(v) => StripMode::KeepTail(v + 1), | ||
} | ||
.strip_long_name(name), | ||
Some(_) => new_name, | ||
} | ||
} | ||
} | ||
|
||
static ENUMS: Lazy<HashMap<&str, (&str, i32)>> = Lazy::new(|| { | ||
// -N translates to StripMode::StripFront(N) | ||
// N translates to StripMode::KeepFront(N) | ||
let mut map = HashMap::new(); | ||
map.insert("HAPI_License", ("auto", -2)); | ||
map.insert("HAPI_Result", ("HapiResult", 2)); | ||
map.insert("HAPI_StatusType", ("auto", -2)); | ||
map.insert("HAPI_State", ("auto", 2)); | ||
map.insert("HAPI_PDG_WorkItemState", ("PdgWorkItemState", -1)); | ||
map.insert("HAPI_PDG_EventType", ("PdgEventType", -3)); | ||
map.insert("HAPI_PDG_State", ("PdgState", -1)); | ||
map.insert("HAPI_CacheProperty", ("auto", -2)); | ||
map.insert("HAPI_EnvIntType", ("auto", -2)); | ||
map.insert("HAPI_PrmScriptType", ("auto", -2)); | ||
map.insert("HAPI_Permissions", ("auto", -2)); | ||
map.insert("HAPI_ParmType", ("auto", 2)); | ||
|
||
map.insert("HAPI_PartType", ("auto", -1)); | ||
map.insert("HAPI_StatusVerbosity", ("auto", -1)); | ||
map.insert("HAPI_SessionType", ("auto", -1)); | ||
map.insert("HAPI_PackedPrimInstancingMode", ("auto", -1)); | ||
map.insert("HAPI_RampType", ("auto", -1)); | ||
map.insert("HAPI_ErrorCode", ("auto", -3)); | ||
map.insert("HAPI_NodeFlags", ("auto", -1)); | ||
map.insert("HAPI_NodeType", ("auto", -1)); | ||
map.insert("HAPI_HeightFieldSampling", ("auto", -1)); | ||
map.insert("HAPI_SessionEnvIntType", ("auto", -1)); | ||
map.insert("HAPI_ImagePacking", ("auto", -1)); | ||
map.insert("HAPI_ImageDataFormat", ("auto", -1)); | ||
map.insert("HAPI_XYZOrder", ("auto", -1)); | ||
map.insert("HAPI_RSTOrder", ("auto", -1)); | ||
map.insert("HAPI_TransformComponent", ("auto", -1)); | ||
map.insert("HAPI_CurveOrders", ("auto", -1)); | ||
map.insert("HAPI_InputType", ("auto", -1)); | ||
map.insert("HAPI_GeoType", ("auto", -1)); | ||
map.insert("HAPI_AttributeTypeInfo", ("auto", -1)); | ||
map.insert("HAPI_StorageType", ("auto", -1)); | ||
map.insert("HAPI_VolumeVisualType", ("auto", -1)); | ||
map.insert("HAPI_VolumeType", ("auto", -1)); | ||
map.insert("HAPI_CurveType", ("auto", -1)); | ||
map.insert("HAPI_AttributeOwner", ("auto", -1)); | ||
map.insert("HAPI_GroupType", ("auto", -1)); | ||
map.insert("HAPI_PresetType", ("auto", -1)); | ||
map.insert("HAPI_ChoiceListType", ("auto", -1)); | ||
map.insert("HAPI_InputCurveMethod", ("auto", -1)); | ||
map.insert("HAPI_InputCurveParameterization", ("auto", -1)); | ||
map | ||
}); | ||
|
||
#[derive(Debug)] | ||
struct Rustifier { | ||
visited: RefCell<HashMap<String, Vec<String>>>, | ||
} | ||
|
||
impl ParseCallbacks for Rustifier { | ||
fn enum_variant_name( | ||
&self, | ||
_enum_name: Option<&str>, | ||
_variant_name: &str, | ||
_variant_value: EnumVariantValue, | ||
) -> Option<String> { | ||
if _enum_name.is_none() { | ||
return None; | ||
}; | ||
let name = _enum_name | ||
.unwrap() | ||
.strip_prefix("enum ") | ||
.expect("Not enum?"); | ||
self.visited | ||
.borrow_mut() | ||
.entry(name.to_string()) | ||
.and_modify(|variants| variants.push(_variant_name.to_string())) | ||
.or_default(); | ||
let (_, _mode) = ENUMS.get(name).expect(&format!("Missing enum: {}", name)); | ||
let mode = StripMode::new(*_mode); | ||
let mut striped = mode.strip_long_name(_variant_name); | ||
// Two stripped variant names can collide with each other. We take a dumb approach by | ||
// attempting to strip one more time with increased step | ||
if let Some(vars) = self.visited.borrow_mut().get_mut(name) { | ||
let _stripped = striped.to_string(); | ||
if vars.contains(&_stripped) { | ||
let mode = StripMode::new(*_mode - 1); | ||
striped = mode.strip_long_name(_variant_name); | ||
} else { | ||
vars.push(_stripped); | ||
} | ||
} | ||
Some(heck::AsUpperCamelCase(striped).to_string()) | ||
} | ||
|
||
fn item_name(&self, _item_name: &str) -> Option<String> { | ||
if let Some((rename, _)) = ENUMS.get(_item_name) { | ||
let new_name = match *rename { | ||
"auto" => _item_name | ||
.strip_prefix("HAPI_") | ||
.expect(&format!("{} - not a HAPI enum?", rename)), | ||
n => n, | ||
}; | ||
return Some(new_name.to_string()); | ||
} | ||
None | ||
} | ||
} | ||
|
||
#[derive(FromArgs, Debug)] | ||
/// Houdini engine raw bindings generator. | ||
struct Args { | ||
/// absolute path to Houdini install | ||
#[argh(option)] | ||
hfs: String, | ||
/// directory to output the bindings file. Default to CWD. | ||
#[argh(option)] | ||
outdir: Option<String>, | ||
|
||
/// rust style naming converntion | ||
#[argh(option, default = "true")] | ||
rustify: bool, | ||
} | ||
|
||
fn main() -> anyhow::Result<()> { | ||
let args: Args = argh::from_env(); | ||
let hfs = Path::new(&args.hfs); | ||
if !hfs.is_dir() { | ||
anyhow::bail!("Invalid HFS directory") | ||
} | ||
let out_path = match args.outdir.as_ref() { | ||
Some(dir) => PathBuf::from(dir), | ||
None => std::env::current_dir()?, | ||
} | ||
.join("bindings.rs"); | ||
|
||
let include_dir = hfs.join("toolkit/include/HAPI"); | ||
|
||
let builder = bindgen::Builder::default() | ||
.header("wrapper.h") | ||
.clang_arg(format!("-I{}", include_dir.to_string_lossy())) | ||
.detect_include_paths(true) | ||
.default_enum_style("rust_non_exhaustive".parse().unwrap()) | ||
.bitfield_enum("NodeType") | ||
.bitfield_enum("NodeFlags") | ||
.bitfield_enum("ErrorCode") | ||
.prepend_enum_name(false) | ||
.generate_comments(false) | ||
.derive_copy(true) | ||
.derive_debug(true) | ||
.derive_hash(false) | ||
.derive_eq(false) | ||
.derive_partialeq(false) | ||
.disable_name_namespacing() | ||
// .rustfmt_bindings(true) | ||
.layout_tests(false) | ||
.raw_line(format!( | ||
"// Houdini version {}", | ||
hfs.file_name().unwrap().to_string_lossy() | ||
)) | ||
.raw_line(format!( | ||
"// hapi-sys version {}", | ||
var("CARGO_PKG_VERSION").unwrap() | ||
)); | ||
let builder = if args.rustify { | ||
let callbacks = Box::new(Rustifier { | ||
visited: Default::default(), | ||
}); | ||
builder.parse_callbacks(callbacks) | ||
} else { | ||
builder | ||
}; | ||
builder | ||
.generate() | ||
.context("bindgen failed")? | ||
.write_to_file(out_path.clone()) | ||
.context("Could not write bindings to file")?; | ||
println!("Generated: {}", out_path.to_string_lossy()); | ||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
#ifndef HAPI_RS_WRAPPER_H | ||
#define HAPI_RS_WRAPPER_H | ||
|
||
#include "HAPI.h" | ||
#include "HAPI_Common.h" | ||
#include "HAPI_Version.h" | ||
#include "HAPI_Helpers.h" | ||
#include "HAPI_API.h" | ||
|
||
#endif //HAPI_RS_WRAPPER_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
$env:HFS = "C:\Houdini\19.5.716"; | ||
$env:PATH += ";${env:HFS}\bin" |
Oops, something went wrong.