forbid slot drop and move slot on set

This commit is contained in:
Corwin 2023-04-06 17:16:01 +01:00
parent c608458247
commit 4f19d6c240
No known key found for this signature in database
3 changed files with 67 additions and 31 deletions

View file

@ -158,7 +158,7 @@ impl OamManaged<'_> {
// safety: commit is not reentrant // safety: commit is not reentrant
let unmanaged = unsafe { &mut *self.unmanaged.get() }; let unmanaged = unsafe { &mut *self.unmanaged.get() };
for (object, mut slot) in unsafe { self.object_store.iter() } for (object, slot) in unsafe { self.object_store.iter() }
.map(|item| unsafe { &*item.object.get() }) .map(|item| unsafe { &*item.object.get() })
.filter(|object| object.is_visible()) .filter(|object| object.is_visible())
.zip(unmanaged.iter()) .zip(unmanaged.iter())

View file

@ -15,7 +15,6 @@ use super::attributes::{AffineMode, Attributes};
#[derive(Default, Debug)] #[derive(Default, Debug)]
struct OamFrameModifyables { struct OamFrameModifyables {
up_to: i32,
this_frame_sprites: Vec<SpriteVram>, this_frame_sprites: Vec<SpriteVram>,
frame: u32, frame: u32,
affine_matrix_count: u32, affine_matrix_count: u32,
@ -32,17 +31,42 @@ pub struct OamIterator<'oam> {
frame_data: &'oam UnsafeCell<OamFrameModifyables>, frame_data: &'oam UnsafeCell<OamFrameModifyables>,
} }
/// A slot in Oam that you can write to. Note that you must call [OamSlot::set]
/// or else it is a bug and will panic when dropped.
pub struct OamSlot<'oam> { pub struct OamSlot<'oam> {
slot: usize, slot: usize,
frame_data: &'oam UnsafeCell<OamFrameModifyables>, frame_data: &'oam UnsafeCell<OamFrameModifyables>,
} }
impl Drop for OamSlot<'_> {
#[track_caller]
fn drop(&mut self) {
panic!("Dropping an OamSlot is a bug in your code. Use the slot by calling set (this consumes the slot) or don't obtain one. See documentation for notes on potential pitfalls.")
}
}
impl OamSlot<'_> { impl OamSlot<'_> {
pub fn set(&mut self, object: &ObjectUnmanaged) { /// Set the slot in OAM to contain the sprite given.
pub fn set(mut self, object: &ObjectUnmanaged) {
let mut attributes = object.attributes; let mut attributes = object.attributes;
// SAFETY: This function is not reentrant and we currently hold a mutable borrow of the [UnmanagedOAM]. // SAFETY: This function is not reentrant and we currently hold a mutable borrow of the [UnmanagedOAM].
let frame_data = unsafe { &mut *self.frame_data.get() }; let frame_data = unsafe { &mut *self.frame_data.get() };
Self::handle_affine(&mut attributes, frame_data, object);
self.set_bytes(attributes.bytes());
frame_data.this_frame_sprites.push(object.sprite.clone());
// don't call the drop implementation.
// okay as none of the fields we have have drop implementations.
core::mem::forget(self);
}
fn handle_affine(
attributes: &mut Attributes,
frame_data: &mut OamFrameModifyables,
object: &ObjectUnmanaged,
) {
if let Some(affine_matrix) = &object.affine_matrix { if let Some(affine_matrix) = &object.affine_matrix {
if affine_matrix.frame_count() != frame_data.frame { if affine_matrix.frame_count() != frame_data.frame {
affine_matrix.set_frame_count(frame_data.frame); affine_matrix.set_frame_count(frame_data.frame);
@ -57,12 +81,6 @@ impl OamSlot<'_> {
attributes.set_affine_matrix(affine_matrix.location() as u16); attributes.set_affine_matrix(affine_matrix.location() as u16);
} }
self.set_bytes(attributes.bytes());
frame_data.this_frame_sprites.push(object.sprite.clone());
frame_data.up_to = self.slot as i32;
} }
fn set_bytes(&mut self, bytes: [u8; 6]) { fn set_bytes(&mut self, bytes: [u8; 6]) {
@ -93,9 +111,7 @@ impl<'oam> Iterator for OamIterator<'oam> {
impl Drop for OamIterator<'_> { impl Drop for OamIterator<'_> {
fn drop(&mut self) { fn drop(&mut self) {
let last_written = unsafe { &*self.frame_data.get() }.up_to; let number_writen = self.index;
let number_writen = (last_written + 1) as usize;
for idx in number_writen..128 { for idx in number_writen..128 {
unsafe { unsafe {
@ -109,7 +125,6 @@ impl Drop for OamIterator<'_> {
impl OamUnmanaged<'_> { impl OamUnmanaged<'_> {
pub fn iter(&mut self) -> OamIterator<'_> { pub fn iter(&mut self) -> OamIterator<'_> {
let frame_data = self.frame_data.get_mut(); let frame_data = self.frame_data.get_mut();
frame_data.up_to = -1;
frame_data.frame = frame_data.frame.wrapping_add(1); frame_data.frame = frame_data.frame.wrapping_add(1);
frame_data.affine_matrix_count = 0; frame_data.affine_matrix_count = 0;
@ -252,3 +267,39 @@ impl ObjectUnmanaged {
self self
} }
} }
#[cfg(test)]
mod tests {
use crate::{
display::object::{Graphics, Tag},
include_aseprite,
};
use super::*;
#[test_case]
fn object_usage(gba: &mut crate::Gba) {
const GRAPHICS: &Graphics = include_aseprite!(
"../examples/the-purple-night/gfx/objects.aseprite",
"../examples/the-purple-night/gfx/boss.aseprite"
);
const BOSS: &Tag = GRAPHICS.tags().get("Boss");
let (mut gfx, mut loader) = gba.display.object.get_unmanaged();
{
let mut slotter = gfx.iter();
let slot_a = slotter.next().unwrap();
let slot_b = slotter.next().unwrap();
let mut obj = ObjectUnmanaged::new(loader.get_vram_sprite(BOSS.sprite(2)));
obj.show();
slot_b.set(&obj);
slot_a.set(&obj);
}
}
}

View file

@ -23,7 +23,7 @@ dependencies = [
"agb_macros", "agb_macros",
"agb_sound_converter", "agb_sound_converter",
"bare-metal", "bare-metal",
"bitflags 2.0.2", "bitflags 2.1.0",
"modular-bitfield", "modular-bitfield",
"rustc-hash", "rustc-hash",
] ]
@ -113,9 +113,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.0.2" version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "487f1e0fcbe47deb8b0574e646def1c903389d95241dd1bbcc6ce4a715dfc0c1" checksum = "c70beb79cbb5ce9c4f8e20849978f34225931f665bb49efa6982875a4d5facb3"
[[package]] [[package]]
name = "bytemuck" name = "bytemuck"
@ -423,21 +423,6 @@ dependencies = [
] ]
[[package]] [[package]]
<<<<<<< HEAD
<<<<<<< HEAD
=======
name = "slotmap"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342"
dependencies = [
"version_check",
]
[[package]]
>>>>>>> ff9ab890 (fix games)
=======
>>>>>>> bd1a51df (unsafe arena added (may remove later))
name = "static_assertions" name = "static_assertions"
version = "1.1.0" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"