diff --git a/Cargo.lock b/Cargo.lock index a29d8a40..5900a30c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4037,7 +4037,7 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "playdate" -version = "0.2.2" +version = "0.2.3" dependencies = [ "playdate-controls", "playdate-display", @@ -4228,7 +4228,7 @@ dependencies = [ [[package]] name = "playdate-sprite" -version = "0.2.11" +version = "0.3.0" dependencies = [ "playdate-display", "playdate-graphics", @@ -4258,7 +4258,7 @@ dependencies = [ [[package]] name = "playdate-sys" -version = "0.4.4" +version = "0.4.5" dependencies = [ "arrayvec", "playdate-bindgen", diff --git a/Cargo.toml b/Cargo.toml index d1c46103..6519e028 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ lua = { version = "0.1", path = "api/lua", package = "playdate-lua", default-fea menu = { version = "0.2", path = "api/menu", package = "playdate-menu", default-features = false } scoreboards = { version = "0.1", path = "api/scoreboards", package = "playdate-scoreboards", default-features = false } sound = { version = "0.4", path = "api/sound", package = "playdate-sound", default-features = false } -sprite = { version = "0.2", path = "api/sprite", package = "playdate-sprite", default-features = false } +sprite = { version = "0.3", path = "api/sprite", package = "playdate-sprite", default-features = false } system = { version = "0.3", path = "api/system", package = "playdate-system", default-features = false } sys = { version = "0.4", path = "api/sys", package = "playdate-sys", default-features = false } diff --git a/api/playdate/Cargo.toml b/api/playdate/Cargo.toml index af486b37..6115bc92 100644 --- a/api/playdate/Cargo.toml +++ b/api/playdate/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "playdate" -version = "0.2.2" +version = "0.2.3" readme = "README.md" description = "High-level Playdate API" keywords = ["playdate", "sdk", "api", "gamedev"] diff --git a/api/sprite/Cargo.toml b/api/sprite/Cargo.toml index 5793aa79..ac99b2a7 100644 --- a/api/sprite/Cargo.toml +++ b/api/sprite/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "playdate-sprite" -version = "0.2.11" +version = "0.3.0" readme = "README.md" description = "High-level sprite API built on-top of Playdate API" keywords = ["playdate", "sdk", "api", "gamedev"] diff --git a/api/sprite/src/lib.rs b/api/sprite/src/lib.rs index dfb2682e..9a076ccd 100644 --- a/api/sprite/src/lib.rs +++ b/api/sprite/src/lib.rs @@ -1,4 +1,5 @@ #![cfg_attr(not(test), no_std)] +#![feature(const_alloc_layout)] extern crate sys; extern crate alloc; @@ -293,3 +294,45 @@ impl SpriteType for T { type Userdata = ::Userdata; const FREE_ON_DROP: bool = ::FREE_ON_DROP; } + + +pub mod utils { + use core::ops::Deref; + + /// C array syzed at runtime. + #[must_use] + #[repr(transparent)] + pub struct Arr<'t, T>(pub(super) &'t [T]); + + impl Drop for Arr<'_, T> { + fn drop(&mut self) { + let p = self.0.as_ptr() as _; + + #[inline] + const fn inner(len: usize) -> core::alloc::Layout { + if let Ok(l) = core::alloc::Layout::array::(len) { + l + } else { + use core::mem::{size_of, align_of}; + let (size, align) = (size_of::(), align_of::()); + unsafe { core::alloc::Layout::from_size_align_unchecked(size.unchecked_mul(len), align) } + } + } + + let l = inner::(self.0.len()); + unsafe { + // We could simply `sys::allocator::dealloc(p)`, but we have to use SYSTEM GLOBAL allocator, + // which can be a user's custom allocator, not that one in `playdate-sys`. + alloc::alloc::dealloc(p, l); + }; + } + } + + impl Deref for Arr<'_, T> { + type Target = [T]; + fn deref(&self) -> &Self::Target { self.0 } + } + impl AsRef<[T]> for Arr<'_, T> { + fn as_ref(&self) -> &[T] { self.0 } + } +} diff --git a/api/sprite/src/sprite.rs b/api/sprite/src/sprite.rs index 40252113..c4cf5173 100644 --- a/api/sprite/src/sprite.rs +++ b/api/sprite/src/sprite.rs @@ -1,5 +1,15 @@ //! Sprite implementations. +/* +TODO: Cover api-methods: + - [] querySpritesInRect + - [] querySpritesAlongLine + - [] querySpriteInfoAlongLine + - [] overlappingSprites + - [] allOverlappingSprites +*/ + + use core::ffi::c_int; use core::ffi::c_void; use core::ffi::c_float; @@ -18,6 +28,7 @@ use gfx::bitmap::BitmapRef; use gfx::bitmap::BitmapDrawMode; use gfx::bitmap::BitmapFlip; +use crate::utils; use crate::AnySprite; use crate::SpriteApi; use crate::TypedSprite; @@ -524,22 +535,22 @@ impl Sprite { /// /// Equivalent to [`sys::ffi::playdate_sprite::checkCollisions`] #[doc(alias = "sys::ffi::playdate_sprite::check_collisions")] - #[must_use = "Result is borrowed by C-API"] + #[must_use = "Expensive op, allocated array by C-API"] pub fn check_collisions(&self, goal_x: c_float, goal_y: c_float, actual_x: &mut c_float, actual_y: &mut c_float) - -> &[SpriteCollisionInfo] { + -> Option> { let f = self.1.check_collisions(); let mut len: c_int = 0; let ptr = unsafe { f(self.0, goal_x, goal_y, actual_x, actual_y, &mut len) }; if ptr.is_null() || len == 0 { - &[] + None } else { let slice = unsafe { core::slice::from_raw_parts(ptr, len as _) }; - slice + Some(utils::Arr(slice)) } } @@ -553,22 +564,22 @@ impl Sprite { /// /// Equivalent to [`sys::ffi::playdate_sprite::moveWithCollisions`] #[doc(alias = "sys::ffi::playdate_sprite::moveWithCollisions")] - #[must_use = "Result is borrowed by C-API"] + #[must_use = "Expensive op, allocated array by C-API"] pub fn move_with_collisions<'t>(&'t self, goal_x: c_float, goal_y: c_float, actual_x: &mut c_float, actual_y: &mut c_float) - -> &'t [SpriteCollisionInfo] { + -> Option> { let f = self.1.move_with_collisions(); let mut len: c_int = 0; let ptr = unsafe { f(self.0, goal_x, goal_y, actual_x, actual_y, &mut len) }; if ptr.is_null() || len == 0 { - &[] + None } else { let slice = unsafe { core::slice::from_raw_parts(ptr, len as _) }; - slice + Some(utils::Arr(slice)) } } @@ -578,13 +589,18 @@ impl Sprite { /// /// Equivalent to [`sys::ffi::playdate_sprite::overlappingSprites`] #[doc(alias = "sys::ffi::playdate_sprite::overlapping_sprites")] - #[must_use = "Result is borrowed by C-API"] - pub fn overlapping_sprites(&self) -> &[SpriteRef] { + #[must_use = "Expensive op, allocated array by C-API"] + pub fn overlapping_sprites(&self) -> Option> { let f = self.1.overlapping_sprites(); let mut len: c_int = 0; let ptr = unsafe { f(self.0, &mut len) }; - let slice = unsafe { core::slice::from_raw_parts(ptr, len as _) }; - unsafe { core::mem::transmute(slice) } + if ptr.is_null() || len == 0 { + None + } else { + let slice = unsafe { core::slice::from_raw_parts(ptr, len as _) }; + let res = unsafe { core::mem::transmute(slice) }; + Some(utils::Arr(res)) + } } diff --git a/api/sys/Cargo.toml b/api/sys/Cargo.toml index 3a30ff70..cecdf90c 100644 --- a/api/sys/Cargo.toml +++ b/api/sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "playdate-sys" -version = "0.4.4" +version = "0.4.5" build = "src/build.rs" readme = "README.md" description = "Low-level Playdate API bindings" diff --git a/api/sys/src/sys/allocator.rs b/api/sys/src/sys/allocator.rs index d76cc6d6..6c08d461 100644 --- a/api/sys/src/sys/allocator.rs +++ b/api/sys/src/sys/allocator.rs @@ -34,7 +34,7 @@ unsafe impl GlobalAlloc for PlaydateAllocator { #[inline] unsafe fn alloc(&self, layout: Layout) -> *mut u8 { realloc(core::ptr::null_mut(), layout.size()) as *mut u8 } #[inline] - unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { realloc(ptr as *mut c_void, 0); } + unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { dealloc(ptr as *mut c_void); } #[inline] unsafe fn realloc(&self, ptr: *mut u8, _layout: Layout, new_size: usize) -> *mut u8 { realloc(ptr as *mut c_void, new_size) as *mut u8 @@ -56,3 +56,8 @@ unsafe fn realloc(ptr: *mut c_void, size: usize) -> *mut c_void { }); f(ptr, size) } + + +#[track_caller] +#[inline(always)] +pub unsafe fn dealloc(ptr: *mut c_void) { realloc(ptr, 0); }