Skip to content

Commit

Permalink
Add cached api end points (part 2) (#131)
Browse files Browse the repository at this point in the history
* Add cached api end points (part 2) (following #130)

* Refactoring fs api (#43), fix dependants that uses fs api

* Fix fs dependants

* Small fixes for some lints
  • Loading branch information
boozook authored Sep 27, 2023
1 parent 65f3e25 commit 85d68f3
Show file tree
Hide file tree
Showing 27 changed files with 705 additions and 565 deletions.
12 changes: 6 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ repository = "https://github.com/boozook/playdate.git"
color = { version = "0.1", path = "api/color", package = "playdate-color", default-features = false }
ctrl = { version = "0.1", path = "api/ctrl", package = "playdate-controls", default-features = false }
display = { version = "0.3", path = "api/display", package = "playdate-display", default-features = false }
fs = { version = "0.1", path = "api/fs", package = "playdate-fs", default-features = false }
fs = { version = "0.2", path = "api/fs", package = "playdate-fs", default-features = false }
gfx = { version = "0.3", path = "api/gfx", package = "playdate-graphics", default-features = false }
menu = { version = "0.1", path = "api/menu", package = "playdate-menu", default-features = false }
sound = { version = "0.1", path = "api/sound", package = "playdate-sound", default-features = false }
Expand Down
2 changes: 1 addition & 1 deletion api/fs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "playdate-fs"
version = "0.1.3"
version = "0.2.0"
readme = "README.md"
description = "High-level file-system API built on-top of Playdate API"
keywords = ["playdate", "sdk", "api", "gamedev"]
Expand Down
2 changes: 1 addition & 1 deletion api/fs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

High-level interface to file-system on-top of `playdate-sys` crate.

🚨 Before the version `0.3` API is highly unstable and subject to change. After that old versions will yanked.
⚠️ Until the version `0.3` API is unstable and can be changed partially.



Expand Down
17 changes: 6 additions & 11 deletions api/fs/examples/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,12 @@ use core::ffi::*;
use core::ptr::null_mut;
use alloc::string::String;

use fs::FileSystem;
use sys::ffi::*;
use fs::options::FileOptionsExt;
use fs::options::OpenOptions;
use fs::Path;
use fs::prelude::*;


fn list_bundle_dir() -> Result<(), fs::error::ApiError> {
let fs = fs::Fs::new()?;
let fs = Fs::Default();
let include_hidden = true;
println!("Listing root dir...");
fs.read_dir("/", |path| println!(" {path}"), include_hidden)?;
Expand All @@ -30,7 +27,7 @@ const FILE: &Path = "temp/temp-file";


fn write_file() -> Result<(), fs::error::ApiError> {
let fs = fs::Fs::new()?;
let fs = Fs::Cached();

let exists = fs.metadata(FILE).is_ok();

Expand All @@ -46,7 +43,7 @@ fn write_file() -> Result<(), fs::error::ApiError> {
let text = "Hello, World!";
println!("writing '{text}' to '{FILE}'");

let mut file = FileOptions::new().write(true).open_using(FILE, &fs)?;
let mut file = fs.open(FILE, FileOptions::new().write(true))?;
let bytes_written = fs.write(&mut file, text.as_bytes())?;
println!("written {bytes_written} bytes");

Expand All @@ -55,7 +52,7 @@ fn write_file() -> Result<(), fs::error::ApiError> {


fn read_file() -> Result<(), fs::error::ApiError> {
let fs = fs::Fs::new()?;
let fs = Fs::Cached();

println!("reading file metadata");
let info = fs.metadata(&FILE)?;
Expand All @@ -66,9 +63,7 @@ fn read_file() -> Result<(), fs::error::ApiError> {
println!("preparing buffer for {} bytes", info.size);
let mut buf = vec![0_u8; info.size as usize];

let mut file = FileOptions::new().read(true)
.read_data(true)
.open_using(FILE, &fs)?;
let mut file = fs.open(FILE, FileOptions::new().read(true).read_data(true))?;

println!("reading '{FILE}'");
let bytes_read = file.read(&mut buf, info.size)?;
Expand Down
228 changes: 228 additions & 0 deletions api/fs/src/api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
use core::ffi::c_int;
use core::ffi::c_uint;
use core::ffi::c_char;
use core::ffi::c_void;
use core::ptr::NonNull;

use sys::ffi::playdate_file;
use sys::ffi::FileOptions;
use sys::ffi::FileStat;


/// Default file system api end-point, ZST.
///
/// All calls approximately costs ~3 derefs.
#[derive(Debug, Clone, Copy, core::default::Default)]
pub struct Default;
impl Api for Default {}


/// Cached file system api end-point.
///
/// Useful if you're making many operations on fs.
///
/// Stores one reference, so size on stack is eq `usize`.
///
/// All calls approximately costs ~1 deref.
#[derive(Clone, Copy)]
#[cfg_attr(feature = "bindings-derive-debug", derive(Debug))]
pub struct Cache(&'static playdate_file);

impl core::default::Default for Cache {
fn default() -> Self { Self(sys::api!(file)) }
}

impl From<*const playdate_file> for Cache {
#[inline(always)]
fn from(ptr: *const playdate_file) -> Self { Self(unsafe { ptr.as_ref() }.expect("fs")) }
}

impl From<&'static playdate_file> for Cache {
#[inline(always)]
fn from(r: &'static playdate_file) -> Self { Self(r) }
}

impl From<NonNull<playdate_file>> for Cache {
#[inline(always)]
fn from(ptr: NonNull<playdate_file>) -> Self { Self(unsafe { ptr.as_ref() }) }
}

impl From<&'_ NonNull<playdate_file>> for Cache {
#[inline(always)]
fn from(ptr: &NonNull<playdate_file>) -> Self { Self(unsafe { ptr.as_ref() }) }
}


impl Api for Cache {
#[inline(always)]
fn close(&self) -> defs::FnClose { self.0.close.expect("close") }

#[inline(always)]
fn flush(&self) -> defs::FnFlush { self.0.flush.expect("flush") }

#[inline(always)]
fn geterr(&self) -> defs::FnGeterr { self.0.geterr.expect("geterr") }

#[inline(always)]
fn listfiles(&self) -> defs::FnListfiles { self.0.listfiles.expect("listfiles") }

#[inline(always)]
fn mkdir(&self) -> defs::FnMkdir { self.0.mkdir.expect("mkdir") }

#[inline(always)]
fn open(&self) -> defs::FnOpen { self.0.open.expect("open") }

#[inline(always)]
fn read(&self) -> defs::FnRead { self.0.read.expect("read") }

#[inline(always)]
fn rename(&self) -> defs::FnRename { self.0.rename.expect("rename") }

#[inline(always)]
fn seek(&self) -> defs::FnSeek { self.0.seek.expect("seek") }

#[inline(always)]
fn stat(&self) -> defs::FnStat { self.0.stat.expect("stat") }

#[inline(always)]
fn tell(&self) -> defs::FnTell { self.0.tell.expect("tell") }

#[inline(always)]
fn unlink(&self) -> defs::FnUnlink { self.0.unlink.expect("unlink") }

#[inline(always)]
fn write(&self) -> defs::FnWrite { self.0.write.expect("write") }
}


pub trait Api {
/// Returns [`sys::ffi::playdate_file::close`].
#[doc(alias = "sys::ffi::playdate_file::close")]
#[inline(always)]
fn close(&self) -> defs::FnClose { *sys::api!(file.close) }

/// Returns [`sys::ffi::playdate_file::flush`].
#[doc(alias = "sys::ffi::playdate_file::flush")]
#[inline(always)]
fn flush(&self) -> defs::FnFlush { *sys::api!(file.flush) }

/// Returns [`sys::ffi::playdate_file::geterr`].
#[doc(alias = "sys::ffi::playdate_file::geterr")]
#[inline(always)]
fn geterr(&self) -> defs::FnGeterr { *sys::api!(file.geterr) }

/// Returns [`sys::ffi::playdate_file::listfiles`].
#[doc(alias = "sys::ffi::playdate_file::listfiles")]
#[inline(always)]
fn listfiles(&self) -> defs::FnListfiles { *sys::api!(file.listfiles) }

/// Returns [`sys::ffi::playdate_file::mkdir`].
#[doc(alias = "sys::ffi::playdate_file::mkdir")]
#[inline(always)]
fn mkdir(&self) -> defs::FnMkdir { *sys::api!(file.mkdir) }

/// Returns [`sys::ffi::playdate_file::open`].
#[doc(alias = "sys::ffi::playdate_file::open")]
#[inline(always)]
fn open(&self) -> defs::FnOpen { *sys::api!(file.open) }

/// Returns [`sys::ffi::playdate_file::read`].
#[doc(alias = "sys::ffi::playdate_file::read")]
#[inline(always)]
fn read(&self) -> defs::FnRead { *sys::api!(file.read) }

/// Returns [`sys::ffi::playdate_file::rename`].
#[doc(alias = "sys::ffi::playdate_file::rename")]
#[inline(always)]
fn rename(&self) -> defs::FnRename { *sys::api!(file.rename) }

/// Returns [`sys::ffi::playdate_file::seek`].
#[doc(alias = "sys::ffi::playdate_file::seek")]
#[inline(always)]
fn seek(&self) -> defs::FnSeek { *sys::api!(file.seek) }

/// Returns [`sys::ffi::playdate_file::stat`].
#[doc(alias = "sys::ffi::playdate_file::stat")]
#[inline(always)]
fn stat(&self) -> defs::FnStat { *sys::api!(file.stat) }

/// Returns [`sys::ffi::playdate_file::tell`].
#[doc(alias = "sys::ffi::playdate_file::tell")]
#[inline(always)]
fn tell(&self) -> defs::FnTell { *sys::api!(file.tell) }

/// Returns [`sys::ffi::playdate_file::unlink`].
#[doc(alias = "sys::ffi::playdate_file::unlink")]
#[inline(always)]
fn unlink(&self) -> defs::FnUnlink { *sys::api!(file.unlink) }

/// Returns [`sys::ffi::playdate_file::write`].
#[doc(alias = "sys::ffi::playdate_file::write")]
#[inline(always)]
fn write(&self) -> defs::FnWrite { *sys::api!(file.write) }
}

impl<T: Api> Api for &'_ T {
#[inline(always)]
fn close(&self) -> defs::FnClose { (*self).close() }

#[inline(always)]
fn flush(&self) -> defs::FnFlush { (*self).flush() }

#[inline(always)]
fn geterr(&self) -> defs::FnGeterr { (*self).geterr() }

#[inline(always)]
fn listfiles(&self) -> defs::FnListfiles { (*self).listfiles() }

#[inline(always)]
fn mkdir(&self) -> defs::FnMkdir { (*self).mkdir() }

#[inline(always)]
fn open(&self) -> defs::FnOpen { (*self).open() }

#[inline(always)]
fn read(&self) -> defs::FnRead { (*self).read() }

#[inline(always)]
fn rename(&self) -> defs::FnRename { (*self).rename() }

#[inline(always)]
fn seek(&self) -> defs::FnSeek { (*self).seek() }

#[inline(always)]
fn stat(&self) -> defs::FnStat { (*self).stat() }

#[inline(always)]
fn tell(&self) -> defs::FnTell { (*self).tell() }

#[inline(always)]
fn unlink(&self) -> defs::FnUnlink { (*self).unlink() }

#[inline(always)]
fn write(&self) -> defs::FnWrite { (*self).write() }
}


#[doc(hidden)]
mod defs {
#![doc(hidden)]
use super::*;

pub type FnClose = unsafe extern "C" fn(*mut c_void) -> c_int;
pub type FnFlush = unsafe extern "C" fn(*mut c_void) -> c_int;
pub type FnGeterr = unsafe extern "C" fn() -> *const c_char;
pub type FnListfiles = unsafe extern "C" fn(*const c_char,
Option<unsafe extern "C" fn(*const c_char, *mut c_void)>,
*mut c_void,
c_int) -> c_int;
pub type FnMkdir = unsafe extern "C" fn(*const c_char) -> c_int;
pub type FnOpen = unsafe extern "C" fn(*const c_char, FileOptions) -> *mut c_void;
pub type FnRead = unsafe extern "C" fn(*mut c_void, *mut c_void, c_uint) -> c_int;
pub type FnRename = unsafe extern "C" fn(*const c_char, *const c_char) -> c_int;
pub type FnSeek = unsafe extern "C" fn(*mut c_void, c_int, c_int) -> c_int;
pub type FnStat = unsafe extern "C" fn(*const c_char, *mut FileStat) -> c_int;
pub type FnTell = unsafe extern "C" fn(*mut c_void) -> c_int;
pub type FnUnlink = unsafe extern "C" fn(*const c_char, c_int) -> c_int;
pub type FnWrite = unsafe extern "C" fn(*mut c_void, *const c_void, c_uint) -> c_int;
}
Loading

0 comments on commit 85d68f3

Please sign in to comment.