mujoco-rs 4.0.0+mj-3.8.0

A high-level Rust wrapper around the MuJoCo C library, with a native viewer (re-)written in Rust.
Documentation
//! # MuJoCo-rs
//! A wrapper around the MuJoCo C library with a Rust-native viewer.
//! If you're familiar with MuJoCo, this should be pretty straightforward to use as the wrappers
//! mainly encapsulate some C structs or just rename them to match Rust's PascalCase style.
//!
//! The main structs are [`wrappers::mj_model::MjModel`] and [`wrappers::mj_data::MjData`].
//! These two structs (and some others) wrap the C structure in order to achieve memory safety.
//!
//! Their fields aren't publicly exposed and can instead be manipulated through views
//! (e.g., [`MjData::joint`](wrappers::mj_data::MjData::joint) and then [`wrappers::mj_data::MjJointDataInfo::view`]).
//! To access the wrapped attributes directly, call the corresponding `ffi()` methods
//! (e.g., [`MjData::ffi`](wrappers::MjData::ffi)).
//!
//! ## MuJoCo version
//!
//! MuJoCo-rs relies on MuJoCo [3.8.0](https://github.com/google-deepmind/mujoco/releases/tag/3.8.0).
//!
//! ## Documentation
//! A more guided documentation can be obtained [here](https://mujoco-rs.readthedocs.io/en/v4.0.x/).
//!
//! ### Missing library errors
//! Guided documentation also contains information on how to **configure MuJoCo**.
//! MuJoCo-rs cannot fully configure it itself due to MuJoCo being a shared C library. As a result, you may encounter
//! **load-time errors** about **missing libraries**.
//!
//! Information on how to configure MuJoCo and resolve these issues is available
//! [here](https://mujoco-rs.readthedocs.io/en/v4.0.x/installation.html#mujoco).
//!
//! ## 3D viewer
//! The Rust-native viewer is available ([`viewer::MjViewer`]) when the `viewer` / `viewer-ui` feature is enabled,
//! as well as MuJoCo's C++ one ([`crate::cpp_viewer::MjViewerCpp`]).
//! The C++ viewer, however, requires manual compilation of a patched MuJoCo repository,
//! like described [here](https://mujoco-rs.readthedocs.io/en/v4.0.x/installation.html#static-linking).
//!
//! ## Model editing
//! [`MjModel`](wrappers::MjModel) can be procedurally generated through the model editing module.
//! The specification representing the model is [`wrappers::mj_editing::MjSpec`].
//!
//! ## Functions
//! Most functions are wrapped under methods at different structs. Some functions
//! are available under the [`wrappers::fun`] module.
//!
//! If a certain function can't be found, you can use the raw FFI bindings, available under
//! the [`mujoco_c`] module. Note that to access the lower-level ffi structs inside wrappers,
//! `ffi()` or `ffi_mut()` must be called (e.g., [`MjData::ffi`](wrappers::MjData::ffi) and [`MjModel::ffi`](wrappers::MjModel::ffi)).
//!
//! # Cargo features
//! This crate has the following public features:
//! - `viewer`: enables the Rust-native MuJoCo viewer.
//!
//!   - `viewer-ui`: enables the (additional) user UI within the viewer.
//!     This also allows users to add custom [`egui`](https://docs.rs/egui/0.33/egui/) widgets to the viewer.
//!
//! - `cpp-viewer`: enables the Rust wrapper around the C++ MuJoCo viewer.
//!   This requires static linking to a modified fork of MuJoCo, as described in [installation](https://mujoco-rs.readthedocs.io/en/v4.0.x/installation.html#static-linking).
//! - `renderer`: enables offscreen rendering for writing RGB and
//!   depth data to memory or file.
//!
//!   - `renderer-winit-fallback`: enables the invisible window fallback (based on winit) when offscreen
//!     rendering fails to initialize. Note that true offscreen rendering is only available on Linux platforms
//!     when the video driver supports it. On Windows and macOS, this feature must always be
//!     enabled when the `renderer` feature is enabled.
//!
//! - `auto-download-mujoco`: MuJoCo dependency will be automatically downloaded to the specified path.
//!
//!   - This is only available on Linux and Windows.
//!   - The environment variable `MUJOCO_DOWNLOAD_DIR` must be set to the absolute path of the download location.
//!   - Downloaded MuJoCo library is still a shared library. See
//!     [installation](https://mujoco-rs.readthedocs.io/en/v4.0.x/installation.html#mujoco)
//!     for information on complete configuration.
//!
//! By default, no optional features are enabled. Enable the features you need explicitly
//! (e.g. `cargo add mujoco-rs --features "viewer-ui renderer-winit-fallback"` for support
//! with the viewer and the viewer's extra UI, and the render with invisible window as a fallback).
//!
//!
use std::ffi::CStr;

pub mod wrappers;
pub mod prelude;
pub mod util;
pub mod error;


#[cfg(feature = "renderer")]
pub mod renderer;

#[cfg(feature = "viewer")]
pub mod viewer;

#[cfg(feature = "cpp-viewer")]
pub mod cpp_viewer;

#[allow(warnings, clippy::approx_constant)]
/// Raw MuJoCo C and C++ FFI bindings (auto-generated).
pub mod mujoco_c;

#[cfg(any(feature = "viewer", feature = "renderer-winit-fallback"))]
mod winit_gl_base;

#[cfg(any(feature = "viewer", feature = "renderer"))]
pub mod vis_common;


/// Returns the version string of the MuJoCo library.
///
/// # Panics
/// Panics if the MuJoCo version string is not valid UTF-8.
pub fn mujoco_version() -> &'static str {
    let arr = unsafe { mujoco_c::mj_versionString() };
    unsafe { CStr::from_ptr(arr).to_str().unwrap() }
}

/// Returns the version string of the MuJoCo library.
#[deprecated(since = "3.0.0", note = "use `mujoco_version` instead")]
pub fn get_mujoco_version() -> &'static str {
    mujoco_version()
}

#[cfg(test)]
mod tests {
    use crate::mujoco_version;

    #[test]
    fn test_version() {
        let version = mujoco_version();
        assert!(!version.is_empty());
    }


    #[allow(unused)]
    pub(crate) fn test_leaks() {
        use super::*;
        use wrappers::*;
        use std::hint::black_box;

        const N_ITEMS: usize = 10000;
        const N_REPEATS: usize = 1000;
        const EXAMPLE_MODEL: &str = "
        <mujoco>
        <worldbody>
            <light ambient=\"0.2 0.2 0.2\"/>
            <body name=\"ball\">
                <geom name=\"sphere\" pos=\".2 .2 .2\" size=\".1\" rgba=\"0 1 0 1\"/>
                <joint name=\"sphere\" type=\"free\"/>
            </body>

            <geom name=\"floor\" type=\"plane\" size=\"10 10 1\" euler=\"5 0 0\"/>

        </worldbody>
        </mujoco>
        ";

        std::hint::black_box(
            for _ in 0..N_REPEATS {
                let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("failed to load the model.");
                for mut data in (0..N_ITEMS).map(|_| model.make_data()) {
                    data.joint("sphere").unwrap().view_mut(&mut data).qpos[0] /= 2.0;
                    data.step();
                }
            }
        )
    }
}