diff --git a/CHANGELOG.md b/CHANGELOG.md index 6dee7c87..a96a00c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +This is a minor release to fix the build of the docs on [docs.rs/agb](https://docs.rs/agb). + +### Fixed +- Fixed the agb crate's docs.rs build + ## [0.12.0] - 2022/10/11 This version of `agb` has some exciting new features we'd like to highlight and some brand new contributors! diff --git a/agb/src/lib.rs b/agb/src/lib.rs index 693717f9..1c0c587a 100644 --- a/agb/src/lib.rs +++ b/agb/src/lib.rs @@ -22,6 +22,8 @@ #![deny(clippy::needless_pass_by_value)] #![deny(clippy::redundant_closure_for_method_calls)] #![deny(clippy::cloned_instead_of_copied)] +#![deny(rustdoc::broken_intra_doc_links)] +#![deny(rustdoc::private_intra_doc_links)] //! # agb //! `agb` is a library for making games on the Game Boy Advance using the Rust diff --git a/agb/src/save/mod.rs b/agb/src/save/mod.rs index 485cc832..78041dce 100644 --- a/agb/src/save/mod.rs +++ b/agb/src/save/mod.rs @@ -5,17 +5,18 @@ //! There are, broadly speaking, three different kinds of save media that can be //! found in official Game Carts: //! -//! * Battery-Backed SRAM: The simplest kind of save media, which can be accessed -//! like normal memory. You can have SRAM up to 32KiB, and while there exist a -//! few variants this does not matter much for a game developer. +//! * Battery-Backed SRAM: The simplest kind of save media, which can be +//! accessed like normal memory. You can have SRAM up to 32KiB, and while +//! there exist a few variants this does not matter much for a game developer. //! * EEPROM: A kind of save media based on very cheap chips and slow chips. //! These are accessed using a serial interface based on reading/writing bit -//! streams into IO registers. This memory comes in 8KiB and 512 byte versions, -//! which unfortunately cannot be distinguished at runtime. -//! * Flash: A kind of save media based on flash memory. Flash memory can be read -//! like ordinary memory, but writing requires sending commands using multiple -//! IO register spread across the address space. This memory comes in 64KiB -//! and 128KiB variants, which can thankfully be distinguished using a chip ID. +//! streams into IO registers. This memory comes in 8KiB and 512 byte +//! versions, which unfortunately cannot be distinguished at runtime. +//! * Flash: A kind of save media based on flash memory. Flash memory can be +//! read like ordinary memory, but writing requires sending commands using +//! multiple IO register spread across the address space. This memory comes in +//! 64KiB and 128KiB variants, which can thankfully be distinguished using a +//! chip ID. //! //! As these various types of save media cannot be easily distinguished at //! runtime, the kind of media in use should be set manually. @@ -39,30 +40,32 @@ //! //! ## Using save media //! -//! To access save media, use the [`SaveData::new`] method to create a new -//! [`SaveData`] object. Its methods are used to read or write save media. +//! To access save media, use the [`SaveManager::access`] or +//! [`SaveManager::access_with_timer`] methods to create a new [`SaveData`] +//! object. Its methods are used to read or write save media. //! //! Reading data from the savegame is simple. Use [`read`] to copy data from an //! offset in the savegame into a buffer in memory. //! -//! Writing to save media requires you to prepare the area for writing by calling -//! the [`prepare_write`] method to return a [`SavePreparedBlock`], which contains -//! the actual [`write`] method. +//! Writing to save media requires you to prepare the area for writing by +//! calling the [`prepare_write`] method to return a [`SavePreparedBlock`], +//! which contains the actual [`write`] method. //! //! The `prepare_write` method leaves everything in a sector that overlaps the -//! range passed to it in an implementation defined state. On some devices it may -//! do nothing, and on others, it may clear the entire range to `0xFF`. +//! range passed to it in an implementation defined state. On some devices it +//! may do nothing, and on others, it may clear the entire range to `0xFF`. //! -//! Because writes can only be prepared on a per-sector basis, a clear on a range -//! of `4000..5000` on a device with 4096 byte sectors will actually clear a range -//! of `0..8192`. Use [`sector_size`] to find the sector size, or [`align_range`] -//! to directly calculate the range of memory that will be affected by the clear. +//! Because writes can only be prepared on a per-sector basis, a clear on a +//! range of `4000..5000` on a device with 4096 byte sectors will actually clear +//! a range of `0..8192`. Use [`sector_size`] to find the sector size, or +//! [`align_range`] to directly calculate the range of memory that will be +//! affected by the clear. //! //! [`read`]: SaveData::read //! [`prepare_write`]: SaveData::prepare_write //! [`write`]: SavePreparedBlock::write -//! [`sector_size`]: SaveAccess::sector_size -//! [`align_range`]: SaveAccess::align_range +//! [`sector_size`]: SaveData::sector_size +//! [`align_range`]: SaveData::align_range //! //! ## Performance and Other Details //! @@ -78,14 +81,14 @@ //! * Atmel flash chips have a sector size of 128 bytes. Reads to any alignment //! are efficient, however, unaligned writes are extremely slow. //! `prepare_write` does not immediately erase any data. -//! * EEPROM has a sector size of 8 bytes. Unaligned reads and writes are -//! slower than aligned writes, however, this is easily mitigated by the -//! small sector size. +//! * EEPROM has a sector size of 8 bytes. Unaligned reads and writes are slower +//! than aligned writes, however, this is easily mitigated by the small sector +//! size. -use core::ops::Range; use crate::save::utils::Timeout; use crate::sync::{Mutex, RawMutexGuard}; use crate::timer::Timer; +use core::ops::Range; mod asm_utils; mod eeprom; @@ -167,7 +170,12 @@ trait RawSaveAccess: Sync { fn info(&self) -> Result<&'static MediaInfo, Error>; fn read(&self, offset: usize, buffer: &mut [u8], timeout: &mut Timeout) -> Result<(), Error>; fn verify(&self, offset: usize, buffer: &[u8], timeout: &mut Timeout) -> Result; - fn prepare_write(&self, sector: usize, count: usize, timeout: &mut Timeout) -> Result<(), Error>; + fn prepare_write( + &self, + sector: usize, + count: usize, + timeout: &mut Timeout, + ) -> Result<(), Error>; fn write(&self, offset: usize, buffer: &[u8], timeout: &mut Timeout) -> Result<(), Error>; } @@ -175,7 +183,10 @@ static CURRENT_SAVE_ACCESS: Mutex> = Mutex::n fn set_save_implementation(access_impl: &'static dyn RawSaveAccess) { let mut access = CURRENT_SAVE_ACCESS.lock(); - assert!(access.is_none(), "Cannot initialize the savegame engine more than once."); + assert!( + access.is_none(), + "Cannot initialize the savegame engine more than once." + ); *access = Some(access_impl); } @@ -258,7 +269,7 @@ impl SaveData { /// Returns a range that contains all sectors the input range overlaps. /// /// This can be used to calculate which blocks would be erased by a call - /// to [`prepare_write`](`SaveAccess::prepare_write`) + /// to [`prepare_write`](`SaveData::prepare_write`) #[must_use] pub fn align_range(&self, range: Range) -> Range { let shift = self.info.sector_shift; @@ -270,19 +281,21 @@ impl SaveData { /// /// This will erase any data in any sector overlapping the input range. To /// calculate which offset ranges would be affected, use the - /// [`align_range`](`SaveAccess::align_range`) function. + /// [`align_range`](`SaveData::align_range`) function. pub fn prepare_write(&mut self, range: Range) -> Result { self.check_bounds(range.clone())?; if self.info.uses_prepare_write { let range = self.align_range(range.clone()); let shift = self.info.sector_shift; self.access.prepare_write( - range.start >> shift, range.len() >> shift, &mut self.timeout, + range.start >> shift, + range.len() >> shift, + &mut self.timeout, )?; } Ok(SavePreparedBlock { parent: self, - range + range, }) } } @@ -302,11 +315,14 @@ impl<'a> SavePreparedBlock<'a> { pub fn write(&mut self, offset: usize, buffer: &[u8]) -> Result<(), Error> { if buffer.is_empty() { Ok(()) - } else if !self.range.contains(&offset) || - !self.range.contains(&(offset + buffer.len() - 1)) { + } else if !self.range.contains(&offset) + || !self.range.contains(&(offset + buffer.len() - 1)) + { Err(Error::OutOfBounds) } else { - self.parent.access.write(offset, buffer, &mut self.parent.timeout) + self.parent + .access + .write(offset, buffer, &mut self.parent.timeout) } } @@ -454,4 +470,4 @@ impl SaveManager { pub fn access_with_timer(&mut self, timer: Timer) -> Result { SaveData::new(Some(timer)) } -} \ No newline at end of file +} diff --git a/agb/src/sync/statics.rs b/agb/src/sync/statics.rs index 62ec9d1d..69536c6c 100644 --- a/agb/src/sync/statics.rs +++ b/agb/src/sync/statics.rs @@ -78,7 +78,7 @@ unsafe fn transfer_align4_thumb(mut dst: *mut T, mut src: *const T) { } } -#[instruction_set(arm::a32)] +#[cfg_attr(not(doc), instruction_set(arm::a32))] #[allow(unused_assignments)] unsafe fn transfer_align4_arm(mut dst: *mut T, mut src: *const T) { let size = mem::size_of::(); @@ -168,14 +168,14 @@ unsafe fn exchange(dst: *mut T, src: *const T) -> T { } } -#[instruction_set(arm::a32)] +#[cfg_attr(not(doc), instruction_set(arm::a32))] unsafe fn exchange_align4_arm(dst: *mut T, i: u32) -> u32 { let out; asm!("swp {2}, {1}, [{0}]", in(reg) dst, in(reg) i, lateout(reg) out); out } -#[instruction_set(arm::a32)] +#[cfg_attr(not(doc), instruction_set(arm::a32))] unsafe fn exchange_align1_arm(dst: *mut T, i: u8) -> u8 { let out; asm!("swpb {2}, {1}, [{0}]", in(reg) dst, in(reg) i, lateout(reg) out); @@ -220,7 +220,9 @@ pub struct Static { impl Static { /// Creates a new static variable. pub const fn new(val: T) -> Self { - Static { data: UnsafeCell::new(val) } + Static { + data: UnsafeCell::new(val), + } } /// Replaces the current value of the static variable with another, and @@ -260,10 +262,10 @@ unsafe impl Sync for Static {} #[cfg(test)] mod test { - use crate::Gba; use crate::interrupt::Interrupt; use crate::sync::Static; use crate::timer::Divider; + use crate::Gba; fn write_read_concurrency_test_impl(gba: &mut Gba) { let sentinel = [0x12345678; COUNT]; @@ -303,7 +305,7 @@ mod test { // and interrupt if interrupt_seen && no_interrupt_seen { timer.set_enabled(false); - return + return; } if i % 8192 == 0 && i != 0 { @@ -326,4 +328,4 @@ mod test { write_read_concurrency_test_impl::<9>(gba); write_read_concurrency_test_impl::<10>(gba); } -} \ No newline at end of file +} diff --git a/justfile b/justfile index 201ced58..9090733e 100644 --- a/justfile +++ b/justfile @@ -24,6 +24,13 @@ test-release: doctest-agb: (cd agb && cargo test --doc -Z doctest-xcompile) +check-docs: + (cd agb && cargo doc --target=thumbv6m-none-eabi) + just _build_docs agb-fixnum + +_build_docs crate: + (cd "{{crate}}" && cargo doc) + clean: just _all-crates _clean @@ -45,7 +52,7 @@ check-linker-script-consistency: find -type f -name gba.ld -print0 | xargs -0 -n1 cmp -- agb/gba.ld find -type f -name gba_mb.ld -print0 | xargs -0 -n1 cmp -- agb/gba_mb.ld -ci: check-linker-script-consistency build-debug clippy test build-release test-release doctest-agb build-roms build-book +ci: check-linker-script-consistency build-debug clippy test build-release test-release doctest-agb build-roms build-book check-docs build-roms: just _build-rom "examples/the-purple-night" "PURPLENIGHT"