Skip to main content

dear_imgui_rs/
internal.rs

1//! Internal low-level types
2//!
3//! Exposes helpers mirroring Dear ImGui internals (e.g. `ImVector`, data type
4//! markers). These are primarily for advanced integrations; APIs may change.
5//!
6#![allow(
7    clippy::cast_possible_truncation,
8    clippy::cast_sign_loss,
9    clippy::as_conversions
10)]
11use crate::sys;
12use std::ffi::c_int;
13use std::slice;
14
15/// A primary data type
16#[repr(i32)]
17#[derive(Copy, Clone, Debug, Eq, PartialEq)]
18pub enum DataType {
19    I8 = sys::ImGuiDataType_S8 as i32,
20    U8 = sys::ImGuiDataType_U8 as i32,
21    I16 = sys::ImGuiDataType_S16 as i32,
22    U16 = sys::ImGuiDataType_U16 as i32,
23    I32 = sys::ImGuiDataType_S32 as i32,
24    U32 = sys::ImGuiDataType_U32 as i32,
25    I64 = sys::ImGuiDataType_S64 as i32,
26    U64 = sys::ImGuiDataType_U64 as i32,
27    F32 = sys::ImGuiDataType_Float as i32,
28    F64 = sys::ImGuiDataType_Double as i32,
29}
30
31/// Primitive type marker.
32///
33/// If this trait is implemented for a type, it is assumed to have *exactly* the same
34/// representation in memory as the primitive value described by the associated `KIND` constant.
35///
36/// # Safety
37/// The `DataType` *must* have the same representation as the primitive value of `KIND`.
38pub unsafe trait DataTypeKind: Copy {
39    const KIND: DataType;
40}
41
42pub(crate) fn component_count_i32(caller: &str, len: usize) -> i32 {
43    assert!(len > 0, "{caller} requires at least one component");
44    i32::try_from(len).unwrap_or_else(|_| {
45        panic!("{caller} supports at most i32::MAX components");
46    })
47}
48
49pub(crate) fn plot_value_count_i32(caller: &str, len: usize) -> i32 {
50    i32::try_from(len).unwrap_or_else(|_| {
51        panic!("{caller} supports at most i32::MAX values");
52    })
53}
54
55pub(crate) fn len_i32(caller: &str, what: &str, len: usize) -> i32 {
56    i32::try_from(len).unwrap_or_else(|_| {
57        panic!("{caller} supports at most i32::MAX {what}");
58    })
59}
60
61unsafe impl DataTypeKind for i8 {
62    const KIND: DataType = DataType::I8;
63}
64unsafe impl DataTypeKind for u8 {
65    const KIND: DataType = DataType::U8;
66}
67unsafe impl DataTypeKind for i16 {
68    const KIND: DataType = DataType::I16;
69}
70unsafe impl DataTypeKind for u16 {
71    const KIND: DataType = DataType::U16;
72}
73unsafe impl DataTypeKind for i32 {
74    const KIND: DataType = DataType::I32;
75}
76unsafe impl DataTypeKind for u32 {
77    const KIND: DataType = DataType::U32;
78}
79unsafe impl DataTypeKind for i64 {
80    const KIND: DataType = DataType::I64;
81}
82unsafe impl DataTypeKind for u64 {
83    const KIND: DataType = DataType::U64;
84}
85unsafe impl DataTypeKind for f32 {
86    const KIND: DataType = DataType::F32;
87}
88unsafe impl DataTypeKind for f64 {
89    const KIND: DataType = DataType::F64;
90}
91
92unsafe impl DataTypeKind for usize {
93    #[cfg(target_pointer_width = "16")]
94    const KIND: DataType = DataType::U16;
95
96    #[cfg(target_pointer_width = "32")]
97    const KIND: DataType = DataType::U32;
98
99    #[cfg(target_pointer_width = "64")]
100    const KIND: DataType = DataType::U64;
101
102    // Fallback for when we are on a weird system width
103    //
104    #[cfg(not(any(
105        target_pointer_width = "16",
106        target_pointer_width = "32",
107        target_pointer_width = "64"
108    )))]
109    compile_error!(
110        "cannot impl DataTypeKind for usize: unsupported target pointer width. supported values are 16, 32, 64"
111    );
112}
113
114unsafe impl DataTypeKind for isize {
115    #[cfg(target_pointer_width = "16")]
116    const KIND: DataType = DataType::I16;
117
118    #[cfg(target_pointer_width = "32")]
119    const KIND: DataType = DataType::I32;
120
121    #[cfg(target_pointer_width = "64")]
122    const KIND: DataType = DataType::I64;
123
124    // Fallback for when we are on a weird system width
125    //
126    #[cfg(not(any(
127        target_pointer_width = "16",
128        target_pointer_width = "32",
129        target_pointer_width = "64"
130    )))]
131    compile_error!(
132        "cannot impl DataTypeKind for isize: unsupported target pointer width. supported values are 16, 32, 64"
133    );
134}
135
136/// A generic version of the raw imgui-sys ImVector struct types
137///
138/// This provides a safe Rust interface to Dear ImGui's vector type.
139#[repr(C)]
140pub struct ImVector<T> {
141    pub(crate) size: c_int,
142    pub(crate) capacity: c_int,
143    pub(crate) data: *mut T,
144}
145
146impl<T> ImVector<T> {
147    /// Returns the vector as a slice
148    #[inline]
149    pub fn as_slice(&self) -> &[T] {
150        if self.size <= 0 || self.data.is_null() {
151            return &[];
152        }
153        let len = match usize::try_from(self.size) {
154            Ok(len) => len,
155            Err(_) => return &[],
156        };
157        unsafe { slice::from_raw_parts(self.data, len) }
158    }
159
160    /// Returns the vector as a mutable slice
161    #[inline]
162    pub fn as_slice_mut(&mut self) -> &mut [T] {
163        if self.size <= 0 || self.data.is_null() {
164            return &mut [];
165        }
166        let len = match usize::try_from(self.size) {
167            Ok(len) => len,
168            Err(_) => return &mut [],
169        };
170        unsafe { slice::from_raw_parts_mut(self.data, len) }
171    }
172
173    /// Returns the number of elements in the vector
174    #[inline]
175    pub fn len(&self) -> usize {
176        if self.size <= 0 {
177            return 0;
178        }
179        usize::try_from(self.size).unwrap_or(0)
180    }
181
182    /// Returns true if the vector is empty
183    #[inline]
184    pub fn is_empty(&self) -> bool {
185        self.size <= 0
186    }
187}
188
189impl<T> Default for ImVector<T> {
190    fn default() -> Self {
191        Self {
192            size: 0,
193            capacity: 0,
194            data: std::ptr::null_mut(),
195        }
196    }
197}
198
199impl<T> ImVector<T> {
200    /// Returns an iterator over the elements
201    #[inline]
202    pub fn iter(&self) -> slice::Iter<'_, T> {
203        self.as_slice().iter()
204    }
205
206    /// Returns a mutable iterator over the elements
207    #[inline]
208    pub fn iter_mut(&mut self) -> slice::IterMut<'_, T> {
209        self.as_slice_mut().iter_mut()
210    }
211}
212
213/// Cast a bindgen-generated `ImVector_*` to our generic `ImVector<T>` view.
214///
215/// # Safety
216/// `raw` must be a pointer/reference to a C `ImVector` instantiated with the same element type
217/// `T` (layout-compatible). Only use with bindgen-generated `ImVector_*` structs from
218/// `dear-imgui-sys`.
219#[inline]
220pub unsafe fn imvector_cast_ref<T, R>(raw: &R) -> &ImVector<T> {
221    unsafe { &*(raw as *const R as *const ImVector<T>) }
222}
223
224/// Mutable variant of [`imvector_cast_ref`]. See its safety contract.
225///
226/// # Safety
227/// Same as [`imvector_cast_ref`], but additionally the caller must ensure the `ImVector` is
228/// uniquely borrowed for the duration of the returned `&mut` reference.
229#[inline]
230pub unsafe fn imvector_cast_mut<T, R>(raw: &mut R) -> &mut ImVector<T> {
231    unsafe { &mut *(raw as *mut R as *mut ImVector<T>) }
232}
233
234/// Update internal hovered window and input capture flags.
235///
236/// This is a thin wrapper around Dear ImGui's internal
237/// `UpdateHoveredWindowAndCaptureFlags()` helper. It is intended for advanced
238/// platform backends that need to drive ImGui's hovering/capture logic
239/// manually (e.g. when aggregating input from multiple sources).
240///
241/// Most applications and backends do **not** need to call this directly.
242#[doc(alias = "UpdateHoveredWindowAndCaptureFlags")]
243pub fn update_hovered_window_and_capture_flags(mouse_pos: [f32; 2]) {
244    unsafe {
245        let pos = sys::ImVec2 {
246            x: mouse_pos[0],
247            y: mouse_pos[1],
248        };
249        sys::igUpdateHoveredWindowAndCaptureFlags(pos.into());
250    }
251}
252
253/// Marks a type as a transparent wrapper over a raw type
254pub trait RawWrapper {
255    /// Wrapped raw type
256    type Raw;
257    /// Returns an immutable reference to the wrapped raw value
258    ///
259    /// # Safety
260    ///
261    /// It is up to the caller to use the returned raw reference without causing undefined
262    /// behaviour or breaking safety rules.
263    unsafe fn raw(&self) -> &Self::Raw;
264    /// Returns a mutable reference to the wrapped raw value
265    ///
266    /// # Safety
267    ///
268    /// It is up to the caller to use the returned mutable raw reference without causing undefined
269    /// behaviour or breaking safety rules.
270    unsafe fn raw_mut(&mut self) -> &mut Self::Raw;
271}
272
273/// Casting from/to a raw type that has the same layout and alignment as the target type
274///
275/// # Safety
276///
277/// Each function outlines its own safety contract, which generally is
278/// that the cast from `T` to `Self` is valid.
279pub unsafe trait RawCast<T>: Sized {
280    /// Casts an immutable reference from the raw type
281    ///
282    /// # Safety
283    ///
284    /// It is up to the caller to guarantee the cast is valid.
285    #[inline]
286    unsafe fn from_raw(raw: &T) -> &Self {
287        unsafe { &*(raw as *const _ as *const Self) }
288    }
289
290    /// Casts a mutable reference from the raw type
291    ///
292    /// # Safety
293    ///
294    /// It is up to the caller to guarantee the cast is valid.
295    #[inline]
296    unsafe fn from_raw_mut(raw: &mut T) -> &mut Self {
297        unsafe { &mut *(raw as *mut _ as *mut Self) }
298    }
299
300    /// Casts an immutable reference to the raw type
301    ///
302    /// # Safety
303    ///
304    /// It is up to the caller to guarantee the cast is valid.
305    #[inline]
306    unsafe fn raw(&self) -> &T {
307        unsafe { &*(self as *const _ as *const T) }
308    }
309
310    /// Casts a mutable reference to the raw type
311    ///
312    /// # Safety
313    ///
314    /// It is up to the caller to guarantee the cast is valid.
315    #[inline]
316    unsafe fn raw_mut(&mut self) -> &mut T {
317        unsafe { &mut *(self as *mut _ as *mut T) }
318    }
319}
320
321#[cfg(test)]
322mod tests {
323    use super::{component_count_i32, len_i32, plot_value_count_i32};
324
325    #[test]
326    fn component_count_rejects_zero_and_overflow() {
327        assert_eq!(component_count_i32("test", 1), 1);
328        assert!(std::panic::catch_unwind(|| component_count_i32("test", 0)).is_err());
329        assert!(
330            std::panic::catch_unwind(|| component_count_i32("test", (i32::MAX as usize) + 1))
331                .is_err()
332        );
333    }
334
335    #[test]
336    fn plot_value_count_allows_zero_but_rejects_overflow() {
337        assert_eq!(plot_value_count_i32("test", 0), 0);
338        assert_eq!(plot_value_count_i32("test", 1), 1);
339        assert!(
340            std::panic::catch_unwind(|| plot_value_count_i32("test", (i32::MAX as usize) + 1))
341                .is_err()
342        );
343    }
344
345    #[test]
346    fn len_i32_rejects_overflow() {
347        assert_eq!(len_i32("test", "items", 0), 0);
348        assert_eq!(len_i32("test", "items", 1), 1);
349        assert!(
350            std::panic::catch_unwind(|| len_i32("test", "items", (i32::MAX as usize) + 1)).is_err()
351        );
352    }
353}