pub trait IReaperControlSurface: Debug + Downcast {
Show 21 methods fn GetTypeString(&self) -> *const c_char { ... } fn GetDescString(&self) -> *const c_char { ... } fn GetConfigString(&self) -> *const c_char { ... } fn CloseNoReset(&self) { ... } fn Run(&mut self) { ... } fn SetTrackListChange(&self) { ... } fn SetSurfaceVolume(&self, _trackid: *mut MediaTrack, _volume: f64) { ... } fn SetSurfacePan(&self, _trackid: *mut MediaTrack, _pan: f64) { ... } fn SetSurfaceMute(&self, _trackid: *mut MediaTrack, _mute: bool) { ... } fn SetSurfaceSelected(&self, _trackid: *mut MediaTrack, _selected: bool) { ... } fn SetSurfaceSolo(&self, _trackid: *mut MediaTrack, _solo: bool) { ... } fn SetSurfaceRecArm(&self, _trackid: *mut MediaTrack, _recarm: bool) { ... } fn SetPlayState(&self, _play: bool, _pause: bool, _rec: bool) { ... } fn SetRepeatState(&self, _rep: bool) { ... } fn SetTrackTitle(&self, _trackid: *mut MediaTrack, _title: *const c_char) { ... } fn GetTouchState(&self, _trackid: *mut MediaTrack, _isPan: c_int) -> bool { ... } fn SetAutoMode(&self, _mode: c_int) { ... } fn ResetCachedVolPanStates(&self) { ... } fn OnTrackSelection(&self, _trackid: *mut MediaTrack) { ... } fn IsKeyDown(&self, _key: c_int) -> bool { ... } fn Extended(
        &self,
        _call: c_int,
        _parm1: *mut c_void,
        _parm2: *mut c_void,
        _parm3: *mut c_void
    ) -> c_int { ... }
}
Expand description

This is the Rust analog to the C++ virtual base class IReaperControlSurface.

An implementation of this trait can be passed to create_cpp_to_rust_control_surface(). After registering the returned C++ counterpart, REAPER will start invoking the callback methods.

Design

Why do most methods here don’t take &mut self as parameter?

Short answer: Because we follow the spirit of Rust here, which is to fail fast and thereby prevent undefined behavior.

Long answer: Taking self as &mut in control surface methods would give us a dangerous illusion of safety (safety as defined by Rust). It would tell Rust developers “It’s safe here to mutate the state of my control surface struct”. But in reality it’s not safe. Not because of multi-threading (ControlSurfaces methods are invoked by REAPER’s main thread only) but because of reentrancy. That can happen quite easily, just think of this scenario: A track is changed, REAPER notifies us about it by calling a ControlSurface method, thereby causing another change in REAPER which in turn synchronously notifies our ControlSurface again while our first method is still running … and there you go: 2 mutable borrows of self. In a Rust-only world, Rust’s compiler wouldn’t allow us to do that. But Rust won’t save us here because the call comes from “outside”. By not having a &mut self reference, developers are forced to explicitly think about this scenario. One can use a RefCell along with borrow_mut() to still mutate some control surface state and failing fast whenever reentrancy happens - at runtime, by getting a panic. This is not as good as failing fast at compile time but still much better than to run into undefined behavior, which could cause hard-to-find bugs and crash REAPER - that’s the last thing we want! Panicking is not so bad. We can catch it before it reaches REAPER and therefore let REAPER continue running. Ideally it’s observed by the developer when he tests his plugin. Then he can think about how to solve that issue. They might find out that it’s okay and therefore use some unsafe code to prevent the panic. They might find out that they want to check for reentrancy by using try_borrow_mut(). Or they might find out that they want to avoid this situation by just deferring the event handling to the next main loop cycle.

Provided Methods

Implementations

Returns true if the trait object wraps an object of type __T.

Returns a boxed object from a boxed trait object if the underlying object is of type __T. Returns the original boxed trait if it isn’t.

Returns an Rc-ed object from an Rc-ed trait object if the underlying object is of type __T. Returns the original Rc-ed trait if it isn’t.

Returns a reference to the object within the trait object if it is of type __T, or None if it isn’t.

Returns a mutable reference to the object within the trait object if it is of type __T, or None if it isn’t.

Implementors