mujoco_rs/lib.rs
1//! # MuJoCo-rs
2//! A wrapper around the MuJoCo C library with a Rust-native viewer.
3//! If you're familiar with MuJoCo, this should be pretty straightforward to use as the wrappers
4//! mainly encapsulate some C structs or just rename them to match the Rust's PascalCase style.
5//!
6//! The main structs are [`wrappers::mj_model::MjModel`] and [`wrappers::mj_data::MjData`].
7//! These two structs (and some other) wrap the C structure in order to achieve memory safety.
8//!
9//! Their fields aren't publicly exposed and can instead be manipulated through views
10//! (e.g., [`MjData::joint`](wrappers::mj_data::MjData::joint) and then [`wrappers::mj_data::MjJointDataInfo::view`]).
11//! To access the wrapped attributes directly, call the corresponding `ffi()` methods
12//! (e.g., [`MjData::ffi`](wrappers::MjData::ffi))
13//!
14//! ## MuJoCo version
15//!
16//! MuJoCo-rs relies on MuJoCo [3.3.7](https://github.com/google-deepmind/mujoco/releases/tag/3.3.7).
17//!
18//! ## Documentation
19//! A more guided documentation can be obtained [here](https://mujoco-rs.readthedocs.io/en/latest/).
20//!
21//! ## 3D viewer
22//! The Rust-native viewer is available ([`viewer::MjViewer`]), as well as the MuJoCo's original C++
23//! one ([`cpp_viewer::MjViewerCpp`]).
24//! The C++ viewer however requires manual compilation of a patched MuJoCo repository,
25//! like described [here](https://mujoco-rs.readthedocs.io/en/latest/installation.html#static-linking-with-c-viewer).
26//!
27//! ## Model editing
28//! [`MjModel`](wrappers::MjModel) can be procedurally generated through the model editing module.
29//! The specification representing the model is [`wrappers::mj_editing::MjSpec`]
30//!
31//! ## Features
32//! This crate has the following public features:
33//! - `viewer`, which enables the Rust-native viewer ([`viewer::MjViewer`]),
34//! - `cpp-viewer`, which enables the MuJoCo's original viewer (C++ based) ([`cpp_viewer::MjViewerCpp`]),
35//! - `renderer`, which enables the image renderer ([`renderer::MjRenderer`]).
36//!
37//! ## Functions
38//! Most functions are wrapped under methods at different structs. Some functions
39//! are available under the [`wrappers::fun`] module.
40//!
41//! If a certain function can't be found, you can use the raw FFI bindings, available under
42//! the [`mujoco_c`] module. Note that to access the lower-level ffi structs inside of wrappers,
43//! `ffi()` or `ffi_mut()` must be called (e.g., [`MjData::ffi`](wrappers::MjData::ffi) and [`MjModel::ffi`](wrappers::MjModel::ffi)).
44use std::ffi::CStr;
45
46pub mod wrappers;
47pub mod prelude;
48pub mod util;
49
50
51#[cfg(feature = "renderer")]
52pub mod renderer;
53
54#[cfg(feature = "viewer")]
55pub mod viewer;
56
57#[cfg(feature = "cpp-viewer")]
58pub mod cpp_viewer;
59
60#[allow(warnings)]
61pub mod mujoco_c; // raw MuJoCo C and C++ bindings
62
63#[cfg(any(feature = "viewer", feature = "renderer"))]
64mod render_base;
65
66
67/// Returns the version string of the MuJoCo library.
68pub fn get_mujoco_version() -> &'static str {
69 let arr = unsafe { mujoco_c::mj_versionString() };
70 unsafe { CStr::from_ptr(arr).to_str().unwrap() }
71}
72
73#[cfg(test)]
74mod tests {
75 use crate::get_mujoco_version;
76
77 #[test]
78 fn test_version() {
79 let version = get_mujoco_version();
80 assert!(!version.is_empty());
81 }
82
83
84 #[allow(unused)]
85 pub(crate) fn test_leaks() {
86 use super::*;
87 use wrappers::*;
88 use std::hint::black_box;
89
90 const N_ITEMS: usize = 10000;
91 const N_REPEATS: usize = 1000;
92 const EXAMPLE_MODEL: &str = "
93 <mujoco>
94 <worldbody>
95 <light ambient=\"0.2 0.2 0.2\"/>
96 <body name=\"ball\">
97 <geom name=\"sphere\" pos=\".2 .2 .2\" size=\".1\" rgba=\"0 1 0 1\"/>
98 <joint name=\"sphere\" type=\"free\"/>
99 </body>
100
101 <geom name=\"floor\" type=\"plane\" size=\"10 10 1\" euler=\"5 0 0\"/>
102
103 </worldbody>
104 </mujoco>
105 ";
106
107 std::hint::black_box(
108 for _ in 0..N_REPEATS {
109 let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("failed to load the model.");
110 for mut data in (0..N_ITEMS).map(|_| model.make_data()) {
111 data.joint("sphere").unwrap().view_mut(&mut data).qpos[0] /= 2.0;
112 data.step();
113 }
114 }
115 )
116 }
117}