Reorganization of the WASM bindings.cc template

* Move all bindings into a single EMSCRIPTEN_BINDINGS block
* Move all auto generated bindings line to the start of the block
* Alphabetically sort the constants binding lines

PiperOrigin-RevId: 837142009
Change-Id: I218a37dbc0ca6c6f16a455718889c08fe1b41d56
This commit is contained in:
Matija Kecman
2025-11-26 08:42:44 -08:00
committed by Copybara-Service
parent c7e0c01e80
commit 05f194c412
4 changed files with 2314 additions and 2389 deletions
File diff suppressed because it is too large Load Diff
+7 -9
View File
@@ -27,15 +27,13 @@ def generate(
"""Generates all Embind code for the provided enums."""
builder = code_builder.CodeBuilder()
with builder.block('EMSCRIPTEN_BINDINGS(mujoco_enums)'):
for e in sorted(enums, key=lambda e: e.name):
if e.values: # Skip empty enums.
with builder.block(f'enum_<{e.name}>("{e.name}")', braces=False):
names = list(e.values.keys())
for name in names[:-1]:
builder.line(f'.value("{name}", {name})')
builder.line(f'.value("{names[-1]}", {names[-1]});')
builder.newline()
for e in sorted(enums, key=lambda e: e.name):
if e.values: # Skip empty enums.
with builder.block(f'enum_<{e.name}>("{e.name}")', braces=False):
names = list(e.values.keys())
for name in names[:-1]:
builder.line(f'.value("{name}", {name})')
builder.line(f'.value("{names[-1]}", {names[-1]});')
content = builder.to_string()
marker = '// {{ ENUM_BINDINGS }}'
+91 -93
View File
@@ -108,49 +108,6 @@ val get_mjFRAMESTRING() { return MakeValArray(mjFRAMESTRING); }
val get_mjVISSTRING() { return MakeValArray3(mjVISSTRING); }
val get_mjRNDSTRING() { return MakeValArray3(mjRNDSTRING); }
EMSCRIPTEN_BINDINGS(mujoco_constants) {
// from mjmodel.h
emscripten::constant("mjPI", mjPI);
emscripten::constant("mjMAXVAL", mjMAXVAL);
emscripten::constant("mjMINMU", mjMINMU);
emscripten::constant("mjMINIMP", mjMINIMP);
emscripten::constant("mjMAXIMP", mjMAXIMP);
emscripten::constant("mjMAXCONPAIR", mjMAXCONPAIR);
emscripten::constant("mjNEQDATA", mjNEQDATA);
emscripten::constant("mjNDYN", mjNDYN);
emscripten::constant("mjNGAIN", mjNGAIN);
emscripten::constant("mjNBIAS", mjNBIAS);
emscripten::constant("mjNREF", mjNREF);
emscripten::constant("mjNIMP", mjNIMP);
emscripten::constant("mjNSOLVER", mjNSOLVER);
// from mjvisualize.h
emscripten::constant("mjNGROUP", mjNGROUP);
emscripten::constant("mjMAXLIGHT", mjMAXLIGHT);
emscripten::constant("mjMAXOVERLAY", mjMAXOVERLAY);
emscripten::constant("mjMAXLINE", mjMAXLINE);
emscripten::constant("mjMAXLINEPNT", mjMAXLINEPNT);
emscripten::constant("mjMAXPLANEGRID", mjMAXPLANEGRID);
// from mujoco.h
emscripten::constant("mjVERSION_HEADER", mjVERSION_HEADER);
// from mjtnum.h
emscripten::constant("mjMINVAL", mjMINVAL);
// emscripten::constant() is designed for simple, compile-time literal values
// (like numbers or a single string literal), complex values need to be
// bound as functions.
emscripten::function("get_mjDISABLESTRING", &get_mjDISABLESTRING);
emscripten::function("get_mjENABLESTRING", &get_mjENABLESTRING);
emscripten::function("get_mjTIMERSTRING", &get_mjTIMERSTRING);
emscripten::function("get_mjLABELSTRING", &get_mjLABELSTRING);
emscripten::function("get_mjFRAMESTRING", &get_mjFRAMESTRING);
emscripten::function("get_mjVISSTRING", &get_mjVISSTRING);
emscripten::function("get_mjRNDSTRING", &get_mjRNDSTRING);
}
// {{ ENUM_BINDINGS }}
// {{ ANONYMOUS_STRUCT_TYPEDEFS }}
@@ -254,48 +211,54 @@ struct MjvScene {
std::vector<MjvGLCamera> camera;
};
// =============== MjModel =============== //
MjModel::MjModel(mjModel *ptr)
MjModel::MjModel(mjModel* ptr)
: ptr_(ptr), opt(&ptr->opt), vis(&ptr->vis), stat(&ptr->stat) {}
MjModel::MjModel(const MjModel &other)
MjModel::MjModel(const MjModel& other)
: ptr_(mj_copyModel(nullptr, other.get())),
opt(&ptr_->opt),
vis(&ptr_->vis),
stat(&ptr_->stat) {}
MjModel::~MjModel() {
if (ptr_) {
mj_deleteModel(ptr_);
}
}
mjModel* MjModel::get() const { return ptr_; }
void MjModel::set(mjModel *ptr) { ptr_ = ptr; }
// TODO(manevi): Consider passing `const MjModel& m` here, mj_makeData uses a const model.
// =============== MjData =============== //
MjData::MjData(MjModel *m) {
mjModel* MjModel::get() const { return ptr_; }
void MjModel::set(mjModel* ptr) { ptr_ = ptr; }
MjData::MjData(MjModel* m) {
model = m->get();
ptr_ = mj_makeData(model);
if (ptr_) {
solver = InitWrapperArray<MjSolverStat>(get()->solver, mjNSOLVER * mjNISLAND);
solver =
InitWrapperArray<MjSolverStat>(get()->solver, mjNSOLVER * mjNISLAND);
timer = InitWrapperArray<MjTimerStat>(get()->timer, mjNTIMER);
warning = InitWrapperArray<MjWarningStat>(get()->warning, mjNWARNING);
}
}
MjData::MjData(const MjModel &model, const MjData &other)
MjData::MjData(const MjModel& model, const MjData& other)
: ptr_(mj_copyData(nullptr, model.get(), other.get())), model(model.get()) {
if (ptr_) {
solver = InitWrapperArray<MjSolverStat>(get()->solver, mjNSOLVER * mjNISLAND);
solver =
InitWrapperArray<MjSolverStat>(get()->solver, mjNSOLVER * mjNISLAND);
timer = InitWrapperArray<MjTimerStat>(get()->timer, mjNTIMER);
warning = InitWrapperArray<MjWarningStat>(get()->warning, mjNWARNING);
}
}
MjData::~MjData() {
if (ptr_) {
mj_deleteData(ptr_);
}
}
mjData* MjData::get() const { return ptr_; }
void MjData::set(mjData *ptr) { ptr_ = ptr; }
void MjData::set(mjData* ptr) { ptr_ = ptr; }
std::vector<MjContact> MjData::contact() const {
return InitWrapperArray<MjContact>(get()->contact, get()->ncon);
@@ -310,7 +273,7 @@ MjvScene::MjvScene() {
camera = InitWrapperArray<MjvGLCamera>(ptr_->camera, 2);
};
MjvScene::MjvScene(MjModel *m, int maxgeom) {
MjvScene::MjvScene(MjModel* m, int maxgeom) {
owned_ = true;
model = m->get();
ptr_ = new mjvScene;
@@ -319,6 +282,7 @@ MjvScene::MjvScene(MjModel *m, int maxgeom) {
lights = InitWrapperArray<MjvLight>(ptr_->lights, mjMAXLIGHT);
camera = InitWrapperArray<MjvGLCamera>(ptr_->camera, 2);
};
MjvScene::~MjvScene() {
if (owned_ && ptr_) {
mjv_freeScene(ptr_);
@@ -327,7 +291,7 @@ MjvScene::~MjvScene() {
}
mjvScene* MjvScene::get() const { return ptr_; }
void MjvScene::set(mjvScene *ptr) { ptr_ = ptr; }
void MjvScene::set(mjvScene* ptr) { ptr_ = ptr; }
// Taken from the python mujoco bindings code for MjvScene Wrapper
int MjvScene::GetSumFlexFaces() const {
@@ -422,7 +386,6 @@ MjSpec::~MjSpec() {
mjSpec *MjSpec::get() const { return ptr_; }
void MjSpec::set(mjSpec *ptr) { ptr_ = ptr; }
// ======= FACTORY AND HELPER FUNCTIONS ========= //
std::unique_ptr<MjModel> loadFromXML_wrapper(std::string filename) {
char error[1000];
mjModel *model = mj_loadXML(filename.c_str(), nullptr, error, sizeof(error));
@@ -464,10 +427,46 @@ int mj_setLengthRange_wrapper(const MjModel& m, const MjData& d, int index, cons
return result;
}
EMSCRIPTEN_BINDINGS(mujoco_structs) {
// {{ WRAPPER_FUNCTIONS }}
EMSCRIPTEN_BINDINGS(mujoco_bindings) {
// {{ ENUM_BINDINGS }}
// {{ STRUCTS_BINDINGS }}
// TODO: should be generated in future CLs -- //
// {{ FUNCTION_BINDINGS }}
function("parseXMLString", &parseXMLString_wrapper, take_ownership());
function("error", &error_wrapper);
emscripten::class_<WasmBuffer<float>>("FloatBuffer")
.constructor<int>()
.class_function("FromArray", &WasmBuffer<float>::FromArray)
.function("GetPointer", &WasmBuffer<float>::GetPointer)
.function("GetElementCount", &WasmBuffer<float>::GetElementCount)
.function("GetView", &WasmBuffer<float>::GetView);
emscripten::class_<WasmBuffer<double>>("DoubleBuffer")
.constructor<int>()
.class_function("FromArray", &WasmBuffer<double>::FromArray)
.function("GetPointer", &WasmBuffer<double>::GetPointer)
.function("GetElementCount", &WasmBuffer<double>::GetElementCount)
.function("GetView", &WasmBuffer<double>::GetView);
emscripten::class_<WasmBuffer<int>>("IntBuffer")
.constructor<int>()
.class_function("FromArray", &WasmBuffer<int>::FromArray)
.function("GetPointer", &WasmBuffer<int>::GetPointer)
.function("GetElementCount", &WasmBuffer<int>::GetElementCount)
.function("GetView", &WasmBuffer<int>::GetView);
emscripten::register_vector<std::string>("mjStringVec");
emscripten::register_vector<int>("mjIntVec");
emscripten::register_vector<mjIntVec>("mjIntVecVec");
emscripten::register_vector<float>("mjFloatVec");
emscripten::register_vector<mjFloatVec>("mjFloatVecVec");
emscripten::register_vector<double>("mjDoubleVec");
emscripten::register_vector<uint8_t>("mjByteVec");
emscripten::register_vector<MjSolverStat>("MjSolverStatVec");
emscripten::register_vector<MjTimerStat>("MjTimerStatVec");
emscripten::register_vector<MjWarningStat>("MjWarningStatVec");
@@ -475,42 +474,41 @@ EMSCRIPTEN_BINDINGS(mujoco_structs) {
emscripten::register_vector<MjvLight>("MjvLightVec");
emscripten::register_vector<MjvGLCamera>("MjvGLCameraVec");
emscripten::register_vector<MjvGeom>("MjvGeomVec");
}
// {{ WRAPPER_FUNCTIONS }}
EMSCRIPTEN_BINDINGS(mujoco_functions) {
function("parseXMLString", &parseXMLString_wrapper, take_ownership());
function("error", &error_wrapper);
// {{ FUNCTION_BINDINGS }}
emscripten::class_<WasmBuffer<float>>("FloatBuffer")
.constructor<int>()
.class_function("FromArray", &WasmBuffer<float>::FromArray)
.function("GetPointer", &WasmBuffer<float>::GetPointer)
.function("GetElementCount", &WasmBuffer<float>::GetElementCount)
.function("GetView", &WasmBuffer<float>::GetView);
emscripten::class_<WasmBuffer<double>>("DoubleBuffer")
.constructor<int>()
.class_function("FromArray", &WasmBuffer<double>::FromArray)
.function("GetPointer", &WasmBuffer<double>::GetPointer)
.function("GetElementCount", &WasmBuffer<double>::GetElementCount)
.function("GetView", &WasmBuffer<double>::GetView);
emscripten::class_<WasmBuffer<int>>("IntBuffer")
.constructor<int>()
.class_function("FromArray", &WasmBuffer<int>::FromArray)
.function("GetPointer", &WasmBuffer<int>::GetPointer)
.function("GetElementCount", &WasmBuffer<int>::GetElementCount)
.function("GetView", &WasmBuffer<int>::GetView);
// register_type gives better type information (val is mapped to any by default)
emscripten::register_vector<std::string>("mjStringVec");
emscripten::register_vector<int>("mjIntVec");
emscripten::register_vector<mjIntVec>("mjIntVecVec");
emscripten::register_vector<float>("mjFloatVec");
emscripten::register_vector<mjFloatVec>("mjFloatVecVec");
emscripten::register_vector<double>("mjDoubleVec");
// register_type() improves type information (val is mapped to any by default)
emscripten::register_type<NumberArray>("number[]");
emscripten::register_type<String>("string");
emscripten::register_vector<uint8_t>("mjByteVec");
emscripten::constant("mjMAXCONPAIR", mjMAXCONPAIR);
emscripten::constant("mjMAXIMP", mjMAXIMP);
emscripten::constant("mjMAXLIGHT", mjMAXLIGHT);
emscripten::constant("mjMAXLINE", mjMAXLINE);
emscripten::constant("mjMAXLINEPNT", mjMAXLINEPNT);
emscripten::constant("mjMAXOVERLAY", mjMAXOVERLAY);
emscripten::constant("mjMAXPLANEGRID", mjMAXPLANEGRID);
emscripten::constant("mjMAXVAL", mjMAXVAL);
emscripten::constant("mjMINIMP", mjMINIMP);
emscripten::constant("mjMINMU", mjMINMU);
emscripten::constant("mjMINVAL", mjMINVAL);
emscripten::constant("mjNBIAS", mjNBIAS);
emscripten::constant("mjNDYN", mjNDYN);
emscripten::constant("mjNEQDATA", mjNEQDATA);
emscripten::constant("mjNGAIN", mjNGAIN);
emscripten::constant("mjNGROUP", mjNGROUP);
emscripten::constant("mjNIMP", mjNIMP);
emscripten::constant("mjNREF", mjNREF);
emscripten::constant("mjNSOLVER", mjNSOLVER);
emscripten::constant("mjPI", mjPI);
emscripten::constant("mjVERSION_HEADER", mjVERSION_HEADER);
// These complex constants are bound using function() rather than constant()
emscripten::function("get_mjDISABLESTRING", &get_mjDISABLESTRING);
emscripten::function("get_mjENABLESTRING", &get_mjENABLESTRING);
emscripten::function("get_mjFRAMESTRING", &get_mjFRAMESTRING);
emscripten::function("get_mjLABELSTRING", &get_mjLABELSTRING);
emscripten::function("get_mjRNDSTRING", &get_mjRNDSTRING);
emscripten::function("get_mjTIMERSTRING", &get_mjTIMERSTRING);
emscripten::function("get_mjVISSTRING", &get_mjVISSTRING);
}
} // namespace mujoco::wasm
+8 -11
View File
@@ -801,17 +801,14 @@ class EnumsGeneratorTest(absltest.TestCase):
def test_generate_enum_bindings(self):
expected_code = """
EMSCRIPTEN_BINDINGS(mujoco_enums) {
enum_<AnotherEnum>("AnotherEnum")
.value("ALPHA", ALPHA)
.value("BETA", BETA);
enum_<TestEnum>("TestEnum")
.value("FIRST_VAL", FIRST_VAL)
.value("SECOND_VAL", SECOND_VAL)
.value("THIRD_VAL", THIRD_VAL);
}""".strip()
enum_<AnotherEnum>("AnotherEnum")
.value("ALPHA", ALPHA)
.value("BETA", BETA);
enum_<TestEnum>("TestEnum")
.value("FIRST_VAL", FIRST_VAL)
.value("SECOND_VAL", SECOND_VAL)
.value("THIRD_VAL", THIRD_VAL);
""".strip()
markers_and_content = enums.generate([
ast_nodes.EnumDecl(