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//! ## Documentation
15//! A more guided documentation can be obtained [here](https://mujoco-rs.readthedocs.io/en/latest/).
16//! 
17//! ## 3D viewer
18//! The Rust-native viewer is available ([`viewer::MjViewer`]), as well as the MuJoCo's original C++
19//! one ([`viewer::MjViewerCpp`]).
20//! The C++ viewer however requires manual compilation of a patched MuJoCo repository,
21//! like described [here](https://mujoco-rs.readthedocs.io/en/latest/installation.html#static-linking-with-c-viewer).
22//! 
23//! ## Model editing
24//! [`MjModel`](wrappers::MjModel) can be procedurally generated through the model editing module.
25//! The specification representing the model is [`wrappers::mj_editing::MjSpec`]
26//! 
27//! ## Features
28//! This crate has the following public features:
29//! - `viewer`, which enables the Rust-native viewer ([`viewer::MjViewer`]),
30//!   - `cpp-viewer`, which additionally enables the MuJoCo's original viewer (C++ based) ([`viewer::MjViewerCpp`]),
31//! - `renderer`, which enables the image renderer ([`renderer::MjRenderer`]).
32//! 
33//! ## Functions
34//! Most functions are wrapped under methods at different structs. Some functions
35//! are available under the [`wrappers::fun`] module.
36//! 
37//! If a certain function can't be found, you can use the raw FFI bindings, available under 
38//! the [`mujoco_c`] module. Note that to access the lower-level ffi structs inside of wrappers,
39//! `ffi()` or `ffi_mut()` must be called (e.g., [`MjData::ffi`](wrappers::MjData::ffi) and [`MjModel::ffi`](wrappers::MjModel::ffi)). 
40
41use std::ffi::CStr;
42
43pub mod wrappers;
44pub mod prelude;
45pub mod util;
46
47
48#[cfg(feature = "renderer")]
49pub mod renderer;
50
51#[cfg(feature = "viewer")]
52pub mod viewer;
53
54#[allow(warnings)]
55pub mod mujoco_c;  // raw MuJoCo C and C++ bindings
56
57
58/// Returns the version string of the MuJoCo library.
59pub fn get_mujoco_version() -> &'static str {
60    let arr = unsafe { mujoco_c::mj_versionString() };
61    unsafe { CStr::from_ptr(arr).to_str().unwrap() }
62}
63
64#[cfg(test)]
65mod tests {
66    use crate::get_mujoco_version;
67
68    #[test]
69    fn test_version() {
70        let version = get_mujoco_version();
71        assert!(!version.is_empty());
72    }
73
74
75    #[allow(unused)]
76    pub(crate) fn test_leaks() {
77        use super::*;
78        use wrappers::*;
79        use std::hint::black_box;
80
81        const N_ITEMS: usize = 10000;
82        const N_REPEATS: usize = 1000;
83        const EXAMPLE_MODEL: &str = "
84        <mujoco>
85        <worldbody>
86            <light ambient=\"0.2 0.2 0.2\"/>
87            <body name=\"ball\">
88                <geom name=\"sphere\" pos=\".2 .2 .2\" size=\".1\" rgba=\"0 1 0 1\"/>
89                <joint name=\"sphere\" type=\"free\"/>
90            </body>
91
92            <geom name=\"floor\" type=\"plane\" size=\"10 10 1\" euler=\"5 0 0\"/>
93
94        </worldbody>
95        </mujoco>
96        ";
97
98        std::hint::black_box(
99            for _ in 0..N_REPEATS {
100                let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("failed to load the model.");
101                for mut data in (0..N_ITEMS).map(|_| model.make_data()) {
102                    data.joint("sphere").unwrap().view_mut(&mut data).qpos[0] /= 2.0;
103                    data.step();
104                }
105            }
106        )
107    }
108}