Expand description
Generates Rust bindings from imping IR.
Generator turns an imping_ir::Ir into formatted Rust source, one
pub mod per IR module, and returns it as Bindings with any
Warnings. The generated code depends only on imping-runtime.
§Examples
let ir = imping_ir::Ir::from_json_str(r#"{
"format_version": { "major": 1, "minor": 0 },
"modules": [{
"name": "target.exe", "architecture": "x64",
"image_base": "0x140000000", "timestamp": "0x64b8f2a1", "image_size": "0xa2b000",
"types": [
{ "id": 0, "name": "float", "kind": "primitive", "primitive": "f32" },
{ "id": 1, "name": "Vector2", "kind": "struct", "size": 8, "align": 4,
"fields": [
{ "name": "x", "type": 0, "offset": 0 },
{ "name": "y", "type": 0, "offset": 4 }
] }
]
}]
}"#)?;
let bindings = imping_codegen::Generator::new().generate(&[("steam", &ir)])?;
assert!(bindings.source().contains("pub mod target"));
assert!(bindings.source().contains("pub struct Vector2"));
assert!(bindings.warnings().is_empty());§Several builds
Each IR file describes one build of the target, and
generate takes them all, each with a label such
as steam_2021. One set of bindings then serves every build: types,
functions and globals are matched by namespace and name, must agree on
their layouts and signatures, and keep each build’s address. An item only
some IRs have is generated too; on the other builds it’s found by another
build’s byte pattern.
§Generated code
- Each module gets a
MODULEidentity, aBuildenum with a variant per label, aninit()that checks the running build and returns which it is, andbuild(). - Types, functions and globals go in one module per namespace
(
target::hw::cVec4for the typeHw::cVec4). - Structs become
#[repr(C)]with explicit padding, bitfield accessors and compile-time checks on size, alignment and every field offset; unions get the same checks. - A struct whose IR field is marked as its base class (a struct at offset
0) derefs to that base and implements
imping_runtime::Inheritsfor it and the base’s own bases, soupcast()turns pointers into base pointers. - Enums become integer newtypes with associated constants, typedefs become type aliases, and opaque types become byte arrays or zero-sized markers.
- Functions become an
unsafe fnplus a module of the same name with the function’s address in each build (RVA_STEAM_2021),rva()for the loaded build,Signature,ptr()andhook(). A hook’s closure gets the function’sOriginalfirst;original.forward()safely makes the call the target was making. A parameter named like a static or enum type in its module gets a trailing_. - Functions tagged
imping-safeget a safefnwhose pointer parameters are references, unless a parameter has no safe form (aWarningsays so). The tag means the function is always fine to call with valid arguments and keeps none of its pointer arguments after returning. - Globals become
imping_runtime::Globalstatics. Structs, unions and enums whose every bit pattern is valid implementimping_runtime::Plain, which makes their globals safe to read and write.
Structs§
- Bindings
- Generated Rust source plus the warnings raised while generating it.
- Builds
Differ - What two builds’ IRs disagree on; see
Error::BuildsDiffer. - Generator
- Generates Rust bindings from the
Irof one or more builds.
Enums§
- Error
- Why
Generator::generatefailed. - Warning
- Something the generator skipped or simplified.