A tiny, zero-cost library that lets you extend a struct with new fields across crate boundaries without recompiling upstream crates.
use extobj::{extobj, ExtObj};
// 1. Declare the extension object type.
extobj!(struct Player);
// 2. In any downstream crate, add fields.
extobj!(impl Player {
pub health: i32,
level: u32,
});
// 3. Use it.
let mut p = ExtObj::<Player>::new();
assert_eq!(p[*health], 0); // Default
p[*health] = 100;
p[*level] = 5;
assert_eq!(p[*health], 100);- Every field becomes a static Var<Player, T> singleton.
- ExtObj is a grow-only vector whose slot i stores a T created by the corresponding Var.
- Construction / destruction are routed through an internal v-table generated by the macro.
- All public APIs are safe; unsafe internals are confined to the crate.
Upstream crate:
// game_core/src/lib.rs
pub use extobj::{extobj, ExtObj};Downstream crate:
// game_ui/src/lib.rs
use game_core::{extobj, ExtObj};
extobj!(impl game_core::Player {
pub visible: bool,
});No recompilation of game_core is required.
If you re-export extobj under a different name, tell the macro:
extobj!(struct Foo, crate_path = my_reexport);MIT OR Apache-2.0