dear-imgui-rs 0.16.0

High-level Rust bindings to Dear ImGui v1.92.9b with docking, WGPU/GL backends, and extensions (ImPlot/ImPlot3D, ImNodes, ImGuizmo, file browser, reflection-based UI)
Documentation
use crate::io::assert_finite_f32;
use crate::sys;
use std::cell::UnsafeCell;

/// Settings and inputs/outputs for imgui-rs
/// This is a transparent wrapper around ImGuiIO
#[repr(transparent)]
pub struct Io(UnsafeCell<sys::ImGuiIO>);

// Ensure the wrapper stays layout-compatible with the sys bindings.
const _: [(); std::mem::size_of::<sys::ImGuiIO>()] = [(); std::mem::size_of::<Io>()];
const _: [(); std::mem::align_of::<sys::ImGuiIO>()] = [(); std::mem::align_of::<Io>()];

impl Io {
    #[inline]
    pub(crate) fn inner(&self) -> &sys::ImGuiIO {
        // Safety: `Io` is a transparent wrapper around the sys `ImGuiIO` value which is owned by
        // Dear ImGui. The value may be mutated by Dear ImGui even while Rust holds `&Io`, so we
        // store it behind `UnsafeCell` to make that interior mutability explicit.
        unsafe { &*self.0.get() }
    }

    #[inline]
    pub(crate) fn inner_mut(&mut self) -> &mut sys::ImGuiIO {
        // Safety: caller has `&mut Io`, so this is a unique Rust borrow for this wrapper.
        unsafe { &mut *self.0.get() }
    }

    fn frame_count(&self) -> i32 {
        let ctx = self.inner().Ctx;
        if ctx.is_null() {
            0
        } else {
            unsafe { (*ctx).FrameCount }
        }
    }

    pub(crate) fn assert_delta_time(&self, caller: &str, delta_time: f32) {
        assert_finite_f32(caller, "delta_time", delta_time);
        if self.frame_count() == 0 {
            assert!(
                delta_time >= 0.0,
                "{caller} delta_time must be non-negative before the first frame"
            );
        } else {
            assert!(
                delta_time > 0.0,
                "{caller} delta_time must be positive after the first frame"
            );
        }
    }
}