reaper_medium/
ptr_wrappers.rs

1//! This module makes low-level structs available in the medium-level API if necessary. This is done
2//! using different strategies, depending on the characteristics of the struct. Sometimes it's just
3//! a type alias, sometimes a wrapper.  
4use crate::CommandId;
5
6use reaper_low::raw;
7
8use std::ptr::NonNull;
9
10// Case 1: Internals exposed: no | vtable: no
11// ==========================================
12
13/// Pointer to a project.
14pub type ReaProject = NonNull<raw::ReaProject>;
15/// Pointer to a track in a project.
16pub type MediaTrack = NonNull<raw::MediaTrack>;
17/// Pointer to an item on a track.
18pub type MediaItem = NonNull<raw::MediaItem>;
19/// Pointer to a take in an item.
20pub type MediaItemTake = NonNull<raw::MediaItem_Take>;
21/// Pointer to an envelope on a track.
22pub type TrackEnvelope = NonNull<raw::TrackEnvelope>;
23/// Pointer to a window.
24pub type Hwnd = NonNull<raw::HWND__>;
25
26// Case 2: Internals exposed: yes | vtable: no
27// ===========================================
28
29/// Pointer to a section (in which actions can be registered).
30///
31/// One example of this is the REAPER main section which contains most of REAPER's actions.
32//
33// It's important that this can't be cloned or copied! Unlike MediaTrack and Co. we have a a
34// function section_from_unique_id() which doesn't require unsafe code because it passes a
35// guaranteed valid `&KbdSectionInfo` to a user-defined closure. The referred object
36// (`KbdSectionInfo`) *must not* be copied, otherwise it would be possible to let the
37// `KbdSectionInfo` escape the closure - without any unsafe code! Validity could not be guaranteed
38// anymore.
39//
40// So if we just use it as reference, why don't we wrap a *reference* of `raw::KbdSectionInfo` in
41// the first place? Then it would be clear that this type is borrow-only! Problem: We actually have
42// an unsafe function that returns this type directly (not as a reference). It's marked as unsafe
43// because returning it means that Rust loses control and consumers have to make sure themselves
44// that the lifetime is long enough. Now, if this wrapper would wrap a reference instead of a raw
45// pointer, we wouldn't be able to return a value at all because we can't return a reference created
46// in a function. Besides, we wouldn't be able to give that reference a correct lifetime annotation.
47#[derive(Eq, PartialEq, Hash, Debug)]
48pub struct KbdSectionInfo(pub(crate) NonNull<raw::KbdSectionInfo>);
49
50impl KbdSectionInfo {
51    /// Returns the number of actions in this section.
52    pub fn action_list_cnt(&self) -> u32 {
53        unsafe { self.0.as_ref() }.action_list_cnt as u32
54    }
55
56    /// Returns the action at the specified index.
57    pub fn get_action_by_index(&self, index: u32) -> Option<KbdCmd<'_>> {
58        let array = unsafe {
59            std::slice::from_raw_parts(
60                self.0.as_ref().action_list,
61                self.0.as_ref().action_list_cnt as usize,
62            )
63        };
64        let raw_kbd_cmd = array.get(index as usize)?;
65        Some(KbdCmd(raw_kbd_cmd))
66    }
67}
68
69/// Borrowed action.
70#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
71pub struct KbdCmd<'a>(pub(crate) &'a raw::KbdCmd);
72
73impl<'a> KbdCmd<'a> {
74    /// Returns the command ID of this action.
75    pub fn cmd(&self) -> CommandId {
76        CommandId(self.0.cmd as _)
77    }
78}
79
80pub(crate) fn require_non_null_panic<T>(ptr: *mut T) -> NonNull<T> {
81    assert!(
82        !ptr.is_null(),
83        "Raw pointer expected to be not null but was null"
84    );
85    unsafe { NonNull::new_unchecked(ptr) }
86}