diff --git a/src/sdl3/audio.rs b/src/sdl3/audio.rs index c6f43638..0202299a 100644 --- a/src/sdl3/audio.rs +++ b/src/sdl3/audio.rs @@ -1173,7 +1173,31 @@ impl Display for AudioStream { } impl AudioStream { + /// Returns the raw SDL_AudioStream pointer. + /// + /// This can be used to call raw SDL functions that aren't wrapped by this crate. + #[doc(alias = "SDL_AudioStream")] + pub fn raw(&self) -> *mut sys::audio::SDL_AudioStream { + self.stream + } + + /// Creates an `AudioStream` from a raw SDL_AudioStream pointer. + /// + /// # Safety + /// + /// - `raw` must be a valid, non-null pointer to an `SDL_AudioStream` + /// - The pointer must not be owned by another wrapper (to avoid double-free) + /// - The caller must ensure the pointer remains valid for the wrapper's lifetime + /// - The caller is responsible for ensuring the stream is properly destroyed + /// (consider using `AudioStreamOwner` if you need automatic cleanup) + #[doc(alias = "SDL_AudioStream")] + pub unsafe fn from_raw(raw: *mut sys::audio::SDL_AudioStream) -> Self { + debug_assert!(!raw.is_null(), "from_raw called with null pointer"); + Self { stream: raw } + } + /// Get the SDL_AudioStream pointer. + #[deprecated(since = "0.18.0", note = "Use `raw()` instead")] #[doc(alias = "SDL_AudioStream")] pub fn stream(&mut self) -> *mut sys::audio::SDL_AudioStream { self.stream @@ -1510,6 +1534,20 @@ pub struct AudioStreamWithCallback { _marker: PhantomData, } +impl Deref for AudioStreamWithCallback { + type Target = AudioStream; + + fn deref(&self) -> &Self::Target { + &self.base_stream + } +} + +impl DerefMut for AudioStreamWithCallback { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.base_stream + } +} + impl Drop for AudioStreamWithCallback { fn drop(&mut self) { // `base_stream` will be dropped automatically. @@ -1524,41 +1562,12 @@ impl Drop for AudioStreamWithCallback { } impl AudioStreamWithCallback { - /// Get the SDL_AudioStream pointer. - pub fn stream(&mut self) -> *mut sys::audio::SDL_AudioStream { - self.base_stream.stream - } - - /// Pauses the audio stream. - pub fn pause(&self) -> Result<(), Error> { - self.base_stream.pause() - } - - /// Resumes the audio stream. - pub fn resume(&self) -> Result<(), Error> { - self.base_stream.resume() - } - - /// Clear any pending data in the stream. - pub fn clear(&self) -> Result<(), Error> { - self.base_stream.clear() - } - - /// Tell the stream that you're done sending data. - pub fn flush(&self) -> Result<(), Error> { - self.base_stream.flush() - } - - pub fn queued_bytes(&self) -> Result { - self.base_stream.queued_bytes() - } - - pub fn available_bytes(&self) -> Result { - self.base_stream.available_bytes() - } - + /// Locks the audio stream for exclusive access to the callback data. + /// + /// This is the only method specific to `AudioStreamWithCallback` - all other + /// `AudioStream` methods are available via `Deref`. pub fn lock(&mut self) -> Option> { - let raw_stream = self.base_stream.stream; + let raw_stream = self.base_stream.raw(); let result = unsafe { sys::audio::SDL_LockAudioStream(raw_stream) }; if result { @@ -1570,14 +1579,6 @@ impl AudioStreamWithCallback { None } } - - pub fn get_gain(&mut self) -> Result { - self.base_stream.get_gain() - } - - pub fn set_gain(&mut self, gain: f32) -> Result<(), Error> { - self.base_stream.set_gain(gain) - } } pub trait AudioRecordingCallback: Send + 'static @@ -1641,7 +1642,7 @@ impl<'a, CB> DerefMut for AudioStreamLockGuard<'a, CB> { impl<'a, CB> Drop for AudioStreamLockGuard<'a, CB> { fn drop(&mut self) { unsafe { - sys::audio::SDL_UnlockAudioStream(self.stream.base_stream.stream); + sys::audio::SDL_UnlockAudioStream(self.stream.base_stream.raw()); } } } diff --git a/src/sdl3/gamepad.rs b/src/sdl3/gamepad.rs index 97ab42a9..c6f00b31 100644 --- a/src/sdl3/gamepad.rs +++ b/src/sdl3/gamepad.rs @@ -748,6 +748,27 @@ pub struct Gamepad { } impl Gamepad { + /// Returns the raw SDL_Gamepad pointer. + /// + /// This can be used to call raw SDL functions that aren't wrapped by this crate. + #[doc(alias = "SDL_Gamepad")] + pub fn raw(&self) -> *mut sys::gamepad::SDL_Gamepad { + self.raw + } + + /// Creates a `Gamepad` from a raw SDL_Gamepad pointer. + /// + /// # Safety + /// + /// - `raw` must be a valid, non-null pointer to an `SDL_Gamepad` + /// - The pointer must not be owned by another wrapper (to avoid double-free) + /// - The caller must ensure the pointer remains valid for the wrapper's lifetime + #[doc(alias = "SDL_Gamepad")] + pub unsafe fn from_raw(raw: *mut sys::gamepad::SDL_Gamepad, subsystem: GamepadSubsystem) -> Self { + debug_assert!(!raw.is_null(), "from_raw called with null pointer"); + Self { subsystem, raw } + } + #[inline] pub fn subsystem(&self) -> &GamepadSubsystem { &self.subsystem diff --git a/src/sdl3/gfx/framerate.rs b/src/sdl3/gfx/framerate.rs index b7d7d0fe..68f59555 100644 --- a/src/sdl3/gfx/framerate.rs +++ b/src/sdl3/gfx/framerate.rs @@ -12,6 +12,28 @@ pub struct FPSManager { } impl FPSManager { + /// Returns the raw FPSmanager pointer. + /// + /// This can be used to call raw SDL_gfx functions that aren't wrapped by this crate. + #[doc(alias = "FPSmanager")] + pub fn raw(&self) -> *mut gfx::framerate::FPSmanager { + self.raw + } + + /// Creates an `FPSManager` from a raw FPSmanager pointer. + /// + /// # Safety + /// + /// - `raw` must be a valid, non-null pointer to an `FPSmanager` + /// - The pointer must not be owned by another wrapper (to avoid double-free) + /// - The caller must ensure the pointer remains valid for the wrapper's lifetime + /// - The pointer must have been allocated with `libc::malloc` (as it will be freed with `libc::free`) + #[doc(alias = "FPSmanager")] + pub unsafe fn from_raw(raw: *mut gfx::framerate::FPSmanager) -> Self { + debug_assert!(!raw.is_null(), "from_raw called with null pointer"); + Self { raw } + } + /// Create the framerate manager. pub fn new() -> FPSManager { unsafe { diff --git a/src/sdl3/gpu/texture.rs b/src/sdl3/gpu/texture.rs index 0a47b3e3..5343bd12 100644 --- a/src/sdl3/gpu/texture.rs +++ b/src/sdl3/gpu/texture.rs @@ -223,8 +223,12 @@ impl Sampler { } } + /// Returns the raw SDL_GPUSampler pointer. + /// + /// This can be used to call raw SDL functions that aren't wrapped by this crate. #[inline] - fn raw(&self) -> *mut SDL_GPUSampler { + #[doc(alias = "SDL_GPUSampler")] + pub fn raw(&self) -> *mut SDL_GPUSampler { self.inner.raw } } diff --git a/src/sdl3/haptic.rs b/src/sdl3/haptic.rs index 7484a61d..70932335 100644 --- a/src/sdl3/haptic.rs +++ b/src/sdl3/haptic.rs @@ -37,6 +37,27 @@ pub struct Haptic { } impl Haptic { + /// Returns the raw SDL_Haptic pointer. + /// + /// This can be used to call raw SDL functions that aren't wrapped by this crate. + #[doc(alias = "SDL_Haptic")] + pub fn raw(&self) -> *mut sys::haptic::SDL_Haptic { + self.raw + } + + /// Creates a `Haptic` from a raw SDL_Haptic pointer. + /// + /// # Safety + /// + /// - `raw` must be a valid, non-null pointer to an `SDL_Haptic` + /// - The pointer must not be owned by another wrapper (to avoid double-free) + /// - The caller must ensure the pointer remains valid for the wrapper's lifetime + #[doc(alias = "SDL_Haptic")] + pub unsafe fn from_raw(raw: *mut sys::haptic::SDL_Haptic, subsystem: HapticSubsystem) -> Self { + debug_assert!(!raw.is_null(), "from_raw called with null pointer"); + Self { subsystem, raw } + } + #[inline] #[doc(alias = "SDL_HapticRumblePlay")] pub fn subsystem(&self) -> &HapticSubsystem { diff --git a/src/sdl3/joystick.rs b/src/sdl3/joystick.rs index e5183e70..4f6e8313 100644 --- a/src/sdl3/joystick.rs +++ b/src/sdl3/joystick.rs @@ -132,6 +132,27 @@ pub struct Joystick { } impl Joystick { + /// Returns the raw SDL_Joystick pointer. + /// + /// This can be used to call raw SDL functions that aren't wrapped by this crate. + #[doc(alias = "SDL_Joystick")] + pub fn raw(&self) -> *mut sys::joystick::SDL_Joystick { + self.raw + } + + /// Creates a `Joystick` from a raw SDL_Joystick pointer. + /// + /// # Safety + /// + /// - `raw` must be a valid, non-null pointer to an `SDL_Joystick` + /// - The pointer must not be owned by another wrapper (to avoid double-free) + /// - The caller must ensure the pointer remains valid for the wrapper's lifetime + #[doc(alias = "SDL_Joystick")] + pub unsafe fn from_raw(raw: *mut sys::joystick::SDL_Joystick, subsystem: JoystickSubsystem) -> Self { + debug_assert!(!raw.is_null(), "from_raw called with null pointer"); + Self { subsystem, raw } + } + #[inline] pub const fn subsystem(&self) -> &JoystickSubsystem { &self.subsystem @@ -455,9 +476,9 @@ impl Joystick { impl Drop for Joystick { #[doc(alias = "SDL_CloseJoystick")] fn drop(&mut self) { - if self.connected() { - unsafe { sys::joystick::SDL_CloseJoystick(self.raw) } - } + // Always close the joystick, regardless of connection status. + // SDL_CloseJoystick is safe to call on disconnected joysticks. + unsafe { sys::joystick::SDL_CloseJoystick(self.raw) } } } diff --git a/src/sdl3/mouse/mod.rs b/src/sdl3/mouse/mod.rs index 9da9ab5a..9e3d5e5b 100644 --- a/src/sdl3/mouse/mod.rs +++ b/src/sdl3/mouse/mod.rs @@ -44,6 +44,27 @@ impl Drop for Cursor { } impl Cursor { + /// Returns the raw SDL_Cursor pointer. + /// + /// This can be used to call raw SDL functions that aren't wrapped by this crate. + #[doc(alias = "SDL_Cursor")] + pub fn raw(&self) -> *mut sys::mouse::SDL_Cursor { + self.raw + } + + /// Creates a `Cursor` from a raw SDL_Cursor pointer. + /// + /// # Safety + /// + /// - `raw` must be a valid, non-null pointer to an `SDL_Cursor` + /// - The pointer must not be owned by another wrapper (to avoid double-free) + /// - The caller must ensure the pointer remains valid for the wrapper's lifetime + #[doc(alias = "SDL_Cursor")] + pub unsafe fn from_raw(raw: *mut sys::mouse::SDL_Cursor) -> Self { + debug_assert!(!raw.is_null(), "from_raw called with null pointer"); + Self { raw } + } + #[doc(alias = "SDL_CreateCursor")] pub fn new( data: &[u8], diff --git a/src/sdl3/pixels.rs b/src/sdl3/pixels.rs index 09c74618..a52ff2c9 100644 --- a/src/sdl3/pixels.rs +++ b/src/sdl3/pixels.rs @@ -13,6 +13,27 @@ pub struct Palette { } impl Palette { + /// Returns the raw SDL_Palette pointer. + /// + /// This can be used to call raw SDL functions that aren't wrapped by this crate. + #[doc(alias = "SDL_Palette")] + pub fn raw(&self) -> *mut pixels::SDL_Palette { + self.raw + } + + /// Creates a `Palette` from a raw SDL_Palette pointer. + /// + /// # Safety + /// + /// - `raw` must be a valid, non-null pointer to an `SDL_Palette` + /// - The pointer must not be owned by another wrapper (to avoid double-free) + /// - The caller must ensure the pointer remains valid for the wrapper's lifetime + #[doc(alias = "SDL_Palette")] + pub unsafe fn from_raw(raw: *mut pixels::SDL_Palette) -> Self { + debug_assert!(!raw.is_null(), "from_raw called with null pointer"); + Self { raw } + } + #[inline] /// Creates a new, uninitialized palette #[doc(alias = "SDL_CreatePalette")] @@ -90,7 +111,6 @@ impl Drop for Palette { } } -impl_raw_accessors!((Palette, *mut pixels::SDL_Palette)); #[test] fn create_palette() { diff --git a/src/sdl3/render.rs b/src/sdl3/render.rs index 0ce1469a..49573c8e 100644 --- a/src/sdl3/render.rs +++ b/src/sdl3/render.rs @@ -2818,6 +2818,20 @@ impl InternalTexture { #[cfg(not(feature = "unsafe_textures"))] impl Texture<'_> { + /// Creates a `Texture` from a raw SDL_Texture pointer. + /// + /// # Safety + /// + /// - `raw` must be a valid, non-null pointer to an `SDL_Texture` + /// - The pointer must not be owned by another wrapper (to avoid double-free) + /// - The caller must ensure the pointer remains valid for the wrapper's lifetime + /// - The texture must have been created by the same renderer that will use it + #[doc(alias = "SDL_Texture")] + pub unsafe fn from_raw(raw: *mut sys::render::SDL_Texture) -> Self { + debug_assert!(!raw.is_null(), "from_raw called with null pointer"); + Self { raw, _marker: PhantomData } + } + /// Gets the texture's internal properties. #[inline] pub fn query(&self) -> TextureQuery { @@ -3053,6 +3067,20 @@ impl Texture<'_> { #[cfg(feature = "unsafe_textures")] impl Texture { + /// Creates a `Texture` from a raw SDL_Texture pointer. + /// + /// # Safety + /// + /// - `raw` must be a valid, non-null pointer to an `SDL_Texture` + /// - The pointer must not be owned by another wrapper (to avoid double-free) + /// - The caller must ensure the pointer remains valid for the wrapper's lifetime + /// - The texture must have been created by the same renderer that will use it + #[doc(alias = "SDL_Texture")] + pub unsafe fn from_raw(raw: *mut sys::render::SDL_Texture) -> Self { + debug_assert!(!raw.is_null(), "from_raw called with null pointer"); + Self { raw } + } + /// Gets the texture's internal properties. #[inline] pub fn query(&self) -> TextureQuery { diff --git a/src/sdl3/sensor.rs b/src/sdl3/sensor.rs index cfa45d58..3fe5defd 100644 --- a/src/sdl3/sensor.rs +++ b/src/sdl3/sensor.rs @@ -119,6 +119,27 @@ pub struct Sensor { } impl Sensor { + /// Returns the raw SDL_Sensor pointer. + /// + /// This can be used to call raw SDL functions that aren't wrapped by this crate. + #[doc(alias = "SDL_Sensor")] + pub fn raw(&self) -> *mut SDL_Sensor { + self.raw + } + + /// Creates a `Sensor` from a raw SDL_Sensor pointer. + /// + /// # Safety + /// + /// - `raw` must be a valid, non-null pointer to an `SDL_Sensor` + /// - The pointer must not be owned by another wrapper (to avoid double-free) + /// - The caller must ensure the pointer remains valid for the wrapper's lifetime + #[doc(alias = "SDL_Sensor")] + pub unsafe fn from_raw(raw: *mut SDL_Sensor, subsystem: SensorSubsystem) -> Self { + debug_assert!(!raw.is_null(), "from_raw called with null pointer"); + Self { subsystem, raw } + } + #[inline] pub const fn subsystem(&self) -> &SensorSubsystem { &self.subsystem