diff --git a/Cargo.lock b/Cargo.lock index 66d9c8f9..a328777c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4128,7 +4128,7 @@ dependencies = [ [[package]] name = "playdate-bindgen" -version = "0.2.2" +version = "0.2.3" dependencies = [ "bindgen", "clap", @@ -4188,9 +4188,10 @@ dependencies = [ [[package]] name = "playdate-controls" -version = "0.3.8" +version = "0.3.9" dependencies = [ "playdate-display", + "playdate-gen-api-shorthands", "playdate-graphics", "playdate-sys", "playdate-system", @@ -4228,8 +4229,9 @@ dependencies = [ [[package]] name = "playdate-display" -version = "0.3.8" +version = "0.3.9" dependencies = [ + "playdate-gen-api-shorthands", "playdate-sys", ] @@ -4241,21 +4243,32 @@ dependencies = [ "playdate-system", ] +[[package]] +name = "playdate-gen-api-shorthands" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "playdate-graphics" -version = "0.6.0" +version = "0.6.1" dependencies = [ "playdate-color", "playdate-display", "playdate-fs", + "playdate-gen-api-shorthands", "playdate-sys", "playdate-system", ] [[package]] name = "playdate-lua" -version = "0.1.4" +version = "0.1.5" dependencies = [ + "playdate-gen-api-shorthands", "playdate-sys", "playdate-system", ] @@ -4271,9 +4284,10 @@ dependencies = [ [[package]] name = "playdate-scoreboards" -version = "0.1.6" +version = "0.1.7" dependencies = [ "erased_set", + "playdate-gen-api-shorthands", "playdate-sys", "playdate-system", ] @@ -4292,9 +4306,10 @@ dependencies = [ [[package]] name = "playdate-sound" -version = "0.4.4" +version = "0.4.5" dependencies = [ "playdate-fs", + "playdate-gen-api-shorthands", "playdate-graphics", "playdate-sys", "playdate-system", @@ -4341,8 +4356,9 @@ dependencies = [ [[package]] name = "playdate-system" -version = "0.3.15" +version = "0.3.16" dependencies = [ + "playdate-gen-api-shorthands", "playdate-sys", ] diff --git a/Cargo.toml b/Cargo.toml index d550cf8c..4bff67a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ device = { version = "0.2", path = "support/device", package = "playdate-device" simulator = { version = "0.1", path = "support/sim-ctrl", package = "playdate-simulator-utils", default-features = false } bindgen = { version = "0.2", path = "support/bindgen", package = "playdate-bindgen", default-features = false } bindgen-cfg = { version = "0.2", path = "support/bindgen-cfg", package = "playdate-bindgen-cfg", default-features = false } +gen-api-shorthands = { version = "0.1", path = "support/gen-api-shorthands", package = "playdate-gen-api-shorthands" } # Deps that used multiple times, # This is to prevent various versions in the deps-tree for faster compilation time @@ -52,6 +53,10 @@ thiserror = "2.0" tokio = { version = "1.43", default-features = false } async-std = { version = "1.13", default-features = false } +proc-macro2 = { version = "1.0" } +quote = { version = "1.0" } +syn = { version = "2.0", features = ["extra-traits", "full", "parsing"] } + [workspace.metadata.playdate.options.assets] dependencies = true diff --git a/api/ctrl/Cargo.toml b/api/ctrl/Cargo.toml index a09737b9..5d75fd38 100644 --- a/api/ctrl/Cargo.toml +++ b/api/ctrl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "playdate-controls" -version = "0.3.8" +version = "0.3.9" readme = "README.md" description = "High-level controls API built on-top of Playdate API" keywords = ["playdate", "sdk", "api", "gamedev"] @@ -23,6 +23,7 @@ bindings-derive-debug = ["sys/bindings-derive-debug"] [dependencies] +gen-api-shorthands.workspace = true sys = { workspace = true, default-features = false } system = { workspace = true, default-features = false } diff --git a/api/ctrl/src/buttons.rs b/api/ctrl/src/buttons.rs index 1655bf36..5eb23118 100644 --- a/api/ctrl/src/buttons.rs +++ b/api/ctrl/src/buttons.rs @@ -3,6 +3,7 @@ use core::fmt::Display; use core::ops::BitAnd; use sys::ffi::PDButtons; +pub use crate::peripherals::buttons_shorthands::*; pub trait PDButtonsExt: Sized + BitAnd { #![allow(non_snake_case)] diff --git a/api/ctrl/src/lib.rs b/api/ctrl/src/lib.rs index 4fe5b87c..1dff3829 100644 --- a/api/ctrl/src/lib.rs +++ b/api/ctrl/src/lib.rs @@ -10,3 +10,11 @@ extern crate sys; pub mod api; pub mod buttons; pub mod peripherals; + +pub mod accelerometer { + pub use crate::peripherals::accelerometer_shorthands::*; +} + +pub mod crank { + pub use crate::peripherals::crank_shorthands::*; +} diff --git a/api/ctrl/src/peripherals.rs b/api/ctrl/src/peripherals.rs index 38a7c44d..f8869167 100644 --- a/api/ctrl/src/peripherals.rs +++ b/api/ctrl/src/peripherals.rs @@ -42,6 +42,7 @@ impl Peripherals where Api: Copy { pub const fn crank(&self) -> Crank { Crank(self.0) } } +#[gen_api_shorthands::gen_shorthands] impl Peripherals { /// Enables specified peripheral. /// @@ -134,6 +135,7 @@ impl Accelerometer { pub const fn new_with(api: Api) -> Self { Self(api) } } +#[gen_api_shorthands::gen_shorthands(pub(crate) mod accelerometer_shorthands)] impl Accelerometer { /// Enables accelerometer only. /// @@ -218,6 +220,7 @@ impl Buttons { pub const fn new_with(api: Api) -> Self { Self(api) } } +#[gen_api_shorthands::gen_shorthands(pub(crate) mod buttons_shorthands)] impl Buttons { /// Returns the current buttons [`State`]. /// @@ -363,6 +366,7 @@ impl Crank { pub const fn new_with(api: Api) -> Self { Self(api) } } +#[gen_api_shorthands::gen_shorthands(pub(crate) mod crank_shorthands)] impl Crank { /// Returns boolean indicating whether or not the crank is folded into the unit. /// diff --git a/api/display/Cargo.toml b/api/display/Cargo.toml index bb7e1e98..a6587bb0 100644 --- a/api/display/Cargo.toml +++ b/api/display/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "playdate-display" -version = "0.3.8" +version = "0.3.9" readme = "README.md" description = "High-level Display API built on-top of Playdate API" keywords = ["playdate", "sdk", "api", "gamedev"] @@ -21,11 +21,9 @@ bindgen-runtime = ["sys/bindgen-runtime"] bindgen-static = ["sys/bindgen-static"] bindings-derive-debug = ["sys/bindings-derive-debug"] - -[dependencies.sys] -workspace = true -default-features = false - +[dependencies] +gen-api-shorthands.workspace = true +sys = { workspace = true, default-features = false } [package.metadata.docs.rs] all-features = false diff --git a/api/display/src/lib.rs b/api/display/src/lib.rs index 5c7c5406..9a93d545 100644 --- a/api/display/src/lib.rs +++ b/api/display/src/lib.rs @@ -5,7 +5,6 @@ use core::ffi::c_float; use core::ffi::c_int; use core::ffi::c_uint; - #[derive(Debug, Clone, Copy)] pub struct Display(Api); @@ -48,7 +47,7 @@ impl Display { bottom: Self::ROWS as _ }; } - +#[gen_api_shorthands::gen_shorthands] impl Display { /// Returns the width of the display, taking the current scale into account; /// diff --git a/api/gfx/Cargo.toml b/api/gfx/Cargo.toml index 7a6e2dca..112e31d1 100644 --- a/api/gfx/Cargo.toml +++ b/api/gfx/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "playdate-graphics" -version = "0.6.0" +version = "0.6.1" readme = "README.md" description = "High-level graphics API built on-top of Playdate API" keywords = ["playdate", "sdk", "api", "gamedev"] @@ -24,6 +24,7 @@ bindings-derive-debug = ["sys/bindings-derive-debug", "color/bindings-derive-deb [dependencies] +gen-api-shorthands.workspace = true sys = { workspace = true, default-features = false } fs = { workspace = true, default-features = false } color = { workspace = true, default-features = false } diff --git a/api/gfx/src/bitmap/bitmap.rs b/api/gfx/src/bitmap/bitmap.rs index 43d9a67d..283802b6 100644 --- a/api/gfx/src/bitmap/bitmap.rs +++ b/api/gfx/src/bitmap/bitmap.rs @@ -601,130 +601,9 @@ impl core::fmt::Debug for BitmapData<'_> { } } +pub use frame_buffer_bitmap as copy_frame_buffer_bitmap; -// -// Global Bitmap-related methods -// - -/// Only valid in the Simulator, -/// returns the debug framebuffer as a bitmap. -/// -/// Returns error on device. -/// -/// This function is shorthand for [`Graphics::debug_bitmap`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::getDebugBitmap`]. -#[doc(alias = "sys::ffi::playdate_graphics::getDebugBitmap")] -#[inline(always)] -pub fn debug_bitmap() -> Result, ApiError> { Graphics::Default().debug_bitmap() } - -/// Returns a bitmap containing the contents of the display buffer. -/// -/// __The system owns this bitmap—​do not free it.__ -/// -/// This function is shorthand for [`Graphics::display_buffer_bitmap`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::getDisplayBufferBitmap`]. -#[doc(alias = "sys::ffi::playdate_graphics::getDisplayBufferBitmap")] -#[inline(always)] -pub fn display_buffer_bitmap() -> Result, Error> { - Graphics::Default().display_buffer_bitmap() -} - -/// Returns a copy the contents of the working frame buffer as a bitmap. -/// -/// The caller is responsible for freeing the returned bitmap, it will automatically on drop. -/// -/// This function is shorthand for [`Graphics::frame_buffer_bitmap`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::copyFrameBufferBitmap`]. -#[doc(alias = "sys::ffi::playdate_graphics::copyFrameBufferBitmap")] -#[inline(always)] -pub fn copy_frame_buffer_bitmap() -> Result, Error> { - Graphics::Default().frame_buffer_bitmap() -} - - -/// Sets the stencil used for drawing. -/// -/// If the `tile` is `true` the stencil image will be tiled. -/// -/// Tiled stencils must have width equal to a multiple of 32 pixels. -/// -/// This function is shorthand for [`Graphics::set_stencil_tiled`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::setStencilImage`]. -#[doc(alias = "sys::ffi::playdate_graphics::setStencilImage")] -#[inline(always)] -pub fn set_stencil_tiled(image: &impl AnyBitmap, tile: bool) { - Graphics::Default().set_stencil_tiled(image, tile) -} - -/// Sets the stencil used for drawing. -/// For a tiled stencil, use [`set_stencil_tiled`] instead. -/// -/// NOTE: Officially deprecated in favor of [`set_stencil_tiled`], which adds a `tile` flag -/// -/// This function is shorthand for [`Graphics::set_stencil`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::setStencil`]. -#[doc(alias = "sys::ffi::playdate_graphics::setStencil")] -#[inline(always)] -pub fn set_stencil(image: &impl AnyBitmap) { Graphics::Default().set_stencil(image) } - -/// Sets the mode used for drawing bitmaps. -/// -/// Note that text drawing uses bitmaps, so this affects how fonts are displayed as well. -/// -/// This function is shorthand for [`Graphics::set_draw_mode`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::setDrawMode`]. -#[doc(alias = "sys::ffi::playdate_graphics::setDrawMode")] -#[inline(always)] -pub fn set_draw_mode(mode: BitmapDrawMode) -> BitmapDrawMode { Graphics::Default().set_draw_mode(mode) } - -/// Push a new drawing context for drawing into the given bitmap. -/// -/// If `target` is [`BitmapRef::null()`], the drawing functions will use the display framebuffer. -/// -/// To push framebuffer to context use [`push_framebuffer_to_context`]. -/// -/// This function is shorthand for [`Graphics::push_context`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::pushContext`]. -#[doc(alias = "sys::ffi::playdate_graphics::pushContext")] -#[inline(always)] -pub fn push_context(target: &impl AnyBitmap) { Graphics::Default().push_context(target) } - -/// Push a new drawing context for drawing into the display framebuffer. -/// -/// This function is shorthand for [`Graphics::push_framebuffer_to_context`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::pushContext`]. -#[doc(alias = "sys::ffi::playdate_graphics::pushContext")] -#[inline(always)] -pub fn push_framebuffer_to_context() { Graphics::Default().push_framebuffer_to_context() } - -/// Pops a context off the stack (if any are left), -/// restoring the drawing settings from before the context was pushed. -/// -/// This function is shorthand for [`Graphics::pop_context`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::popContext`]. -#[doc(alias = "sys::ffi::playdate_graphics::popContext")] -#[inline(always)] -pub fn pop_context() { Graphics::Default().pop_context() } - - +#[gen_api_shorthands::gen_shorthands] impl Graphics { /// Only valid in the Simulator, /// returns the debug framebuffer as a bitmap. diff --git a/api/gfx/src/lib.rs b/api/gfx/src/lib.rs index b44e1366..58afc1df 100644 --- a/api/gfx/src/lib.rs +++ b/api/gfx/src/lib.rs @@ -52,273 +52,6 @@ unsafe fn as_slice_mut(buf: *mut u8) -> Result<&'static mut [u8], ApiError> { } -/// Returns the current display frame buffer. -/// Rows are 32-bit aligned, so the row stride is 52 bytes, with the extra 2 bytes per row ignored. -/// Bytes are MSB-ordered; i.e., the pixel in column 0 is the 0x80 bit of the first byte of the row. -/// -/// This function is shorthand for [`Graphics::get_frame`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::getFrame`]. -#[doc(alias = "sys::ffi::playdate_graphics::getFrame")] -#[inline(always)] -pub fn get_frame() -> Result<&'static mut [u8], ApiError> { Graphics::Default().get_frame() } - - -/// Returns the raw bits in the display buffer, -/// __the last completed frame__. -/// -/// This function is shorthand for [`Graphics::get_display_frame`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::getDisplayFrame`]. -#[doc(alias = "sys::ffi::playdate_graphics::getDisplayFrame")] -#[inline(always)] -pub fn get_display_frame() -> Result<&'static mut [u8], ApiError> { Graphics::Default().get_display_frame() } - -/// After updating pixels in the buffer returned by [`get_frame`], -/// you must tell the graphics system which rows were updated. -/// -/// This function marks a contiguous range of rows as updated -/// (e.g., `markUpdatedRows(0, LCD_ROWS-1)` tells the system to update the entire display). -/// -/// Both `start` and `end` are __included__ in the range. -/// -/// This function is shorthand for [`Graphics::mark_updated_rows`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::markUpdatedRows`]. -#[doc(alias = "sys::ffi::playdate_graphics::markUpdatedRows")] -#[inline(always)] -pub fn mark_updated_rows(start: c_int, end: c_int) { Graphics::Default().mark_updated_rows(start, end) } - -/// Manually flushes the current frame buffer out to the display. -/// This function is automatically called after each pass through the run loop, -/// so there shouldn’t be any need to call it yourself. -/// -/// This function is shorthand for [`Graphics::display`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::display`]. -#[doc(alias = "sys::ffi::playdate_graphics::display")] -#[inline(always)] -pub fn display() { Graphics::Default().display() } - -/// Clears the entire display, filling it with `color`. -/// -/// This function is shorthand for [`Graphics::always`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::clear`]. -#[doc(alias = "sys::ffi::playdate_graphics::clear")] -#[inline(always)] -pub fn clear(color: color::Color) { clear_raw(color.into()) } - - -/// Clears the entire display, filling it with `color`. -/// -/// Same as [`clear`], but without conversion `Color` -> `LCDColor`. -/// That conversion is really cheap, -/// so this function is useful if you're working with `LCDColor` directly. -/// -/// This function is shorthand for [`Graphics::clear_raw`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::clear`]. -#[doc(alias = "sys::ffi::playdate_graphics::clear")] -#[inline(always)] -pub fn clear_raw(color: LCDColor) { Graphics::Default().clear_raw(color) } - -/// Sets the current clip rect in __screen__ coordinates. -/// -/// This function is shorthand for [`Graphics::set_screen_clip_rect`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::setScreenClipRect`]. -#[doc(alias = "sys::ffi::playdate_graphics::setScreenClipRect")] -#[inline(always)] -pub fn set_screen_clip_rect(x: c_int, y: c_int, width: c_int, height: c_int) { - Graphics::Default().set_screen_clip_rect(x, y, width, height) -} - -/// Offsets the origin point for all drawing calls to `x, y` (can be negative). -/// -/// This is useful, for example, for centering a "camera" -/// on a sprite that is moving around a world larger than the screen. -/// -/// This function is shorthand for [`Graphics::set_draw_offset`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::setDrawOffset`]. -#[doc(alias = "sys::ffi::playdate_graphics::setDrawOffset")] -#[inline(always)] -pub fn set_draw_offset(dx: c_int, dy: c_int) { Graphics::Default().set_draw_offset(dx, dy) } - -/// Sets the current clip rect, using __world__ coordinates that is, -/// the given rectangle will be translated by the current drawing offset. -/// -/// The clip rect is cleared at the beginning of each update. -/// -/// This function is shorthand for [`Graphics::set_clip_rect`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::setClipRect`]. -#[doc(alias = "sys::ffi::playdate_graphics::setClipRect")] -#[inline(always)] -pub fn set_clip_rect(x: c_int, y: c_int, width: c_int, height: c_int) { - Graphics::Default().set_clip_rect(x, y, width, height) -} - -/// Clears the current clip rect. -/// -/// This function is shorthand for [`Graphics::clear_clip_rect`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::clearClipRect`]. -#[doc(alias = "sys::ffi::playdate_graphics::clearClipRect")] -#[inline(always)] -pub fn clear_clip_rect() { Graphics::Default().clear_clip_rect() } - -/// Sets the background color shown when the display is offset -/// or for clearing dirty areas in the sprite system. -/// -/// This function is shorthand for [`Graphics::set_background_color`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::setBackgroundColor`]. -#[doc(alias = "sys::ffi::playdate_graphics::setBackgroundColor")] -#[inline(always)] -pub fn set_background_color(color: LCDSolidColor) { Graphics::Default().set_background_color(color) } - - -// -// Geometry -// - -/// Fills the polygon with vertices at the given coordinates -/// (an array of `2 * num_points` ints containing alternating x and y values) -/// using the given `color` and fill, or winding, `rule`. -/// -/// See [wikipedia](https://en.wikipedia.org/wiki/Nonzero-rule) for an explanation of the winding rule. -/// -/// This function is shorthand for [`Graphics::fill_polygon`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::fillPolygon`]. -#[doc(alias = "sys::ffi::playdate_graphics::fillPolygon")] -#[inline(always)] -pub fn fill_polygon(num_points: c_int, coords: &mut [c_int], color: LCDColor, rule: LCDPolygonFillRule) { - Graphics::Default().fill_polygon(num_points, coords, color, rule) -} - -/// Draws a line from `x1, y1` to `x2, y2` with a stroke width of `width`. -/// -/// This function is shorthand for [`Graphics::draw_line`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::drawLine`]. -#[doc(alias = "sys::ffi::playdate_graphics::drawLine")] -#[inline(always)] -pub fn draw_line(x1: c_int, y1: c_int, x2: c_int, y2: c_int, width: c_int, color: LCDColor) { - Graphics::Default().draw_line(x1, y1, x2, y2, width, color) -} - -/// Draws a filled triangle with points at `x1, y1`, `x2, y2`, and `x3, y3`. -/// -/// This function is shorthand for [`Graphics::fill_triangle`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::fillTriangle`]. -#[doc(alias = "sys::ffi::playdate_graphics::fillTriangle")] -#[inline(always)] -pub fn fill_triangle(x1: c_int, y1: c_int, x2: c_int, y2: c_int, x3: c_int, y3: c_int, color: LCDColor) { - Graphics::Default().fill_triangle(x1, y1, x2, y2, x3, y3, color); -} - -/// Draws a `width` by `height` rect at `x, y`. -/// -/// This function is shorthand for [`Graphics::draw_rect`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::drawRect`]. -#[doc(alias = "sys::ffi::playdate_graphics::drawRect")] -#[inline(always)] -pub fn draw_rect(x: c_int, y: c_int, width: c_int, height: c_int, color: LCDColor) { - Graphics::Default().draw_rect(x, y, width, height, color) -} - -/// Draws a filled `width` by `height` rect at `x, y`. -/// -/// This function is shorthand for [`Graphics::fill_rect`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::fillRect`]. -#[doc(alias = "sys::ffi::playdate_graphics::fillRect")] -#[inline(always)] -pub fn fill_rect(x: c_int, y: c_int, width: c_int, height: c_int, color: LCDColor) { - Graphics::Default().fill_rect(x, y, width, height, color) -} - -/// Draw an ellipse stroked inside the rect. -/// -/// Draws an ellipse inside the rectangle `x, y, width, height` of width `line_width` -/// (inset from the rectangle bounds). -/// -/// If `start_angle != end_angle`, this draws an arc between the given angles. -/// -/// Angles are given in degrees, clockwise from due north. -/// -/// This function is shorthand for [`Graphics::draw_ellipse`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::drawEllipse`]. -#[doc(alias = "sys::ffi::playdate_graphics::drawEllipse")] -#[inline(always)] -pub fn draw_ellipse(x: c_int, - y: c_int, - width: c_int, - height: c_int, - line_width: c_int, - start_angle: c_float, - end_angle: c_float, - color: LCDColor) { - Graphics::Default().draw_ellipse(x, y, width, height, line_width, start_angle, end_angle, color) -} - -/// Fills an ellipse inside the rectangle `x, y, width, height`. -/// -/// If `start_angle != end_angle`, this draws a wedge/Pacman between the given angles. -/// -/// Angles are given in degrees, clockwise from due north. -/// -/// This function is shorthand for [`Graphics::fill_ellipse`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::fillEllipse`]. -#[doc(alias = "sys::ffi::playdate_graphics::fillEllipse")] -#[inline(always)] -pub fn fill_ellipse(x: c_int, - y: c_int, - width: c_int, - height: c_int, - start_angle: c_float, - end_angle: c_float, - color: LCDColor) { - Graphics::Default().fill_ellipse(x, y, width, height, start_angle, end_angle, color) -} - - -/// Sets the end cap style used in the line drawing functions. -/// -/// This function is shorthand for [`Graphics::set_line_cap_style`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::setLineCapStyle`]. -#[doc(alias = "sys::ffi::playdate_graphics::setLineCapStyle")] -#[inline(always)] -pub fn set_line_cap_style(end_cap_style: LineCapStyle) { Graphics::Default().set_line_cap_style(end_cap_style) } - - #[derive(Debug, Clone, Copy)] pub struct Graphics(Api); @@ -350,6 +83,7 @@ impl Graphics { pub fn new_with(api: Api) -> Self { Self(api) } } +#[gen_api_shorthands::gen_shorthands] impl Graphics { /// Sets the pixel at `(x,y)` in the current drawing context (by default the screen) to the given `color`. /// Be aware that setting a pixel at a time is not very efficient: diff --git a/api/gfx/src/text.rs b/api/gfx/src/text.rs index b46f9e23..39b040d7 100644 --- a/api/gfx/src/text.rs +++ b/api/gfx/src/text.rs @@ -16,238 +16,7 @@ use crate::Graphics; use crate::bitmap::BitmapRef; use crate::error::{Error, ApiError}; - -/// Draws the given `text` using the provided coords `x`, `y`. -/// -/// Encoding is always `StringEncoding::UTF8`. -/// If another encoding is desired, use [`draw_text_cstr`] instead. -/// -/// If no `font` has been set with [`set_font`], -/// the default system font `Asheville Sans 14 Light` is used. -/// -/// This function is shorthand for [`Graphics::draw_text`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::drawText`]. -#[doc(alias = "sys::ffi::playdate_graphics::drawText")] -#[inline(always)] -pub fn draw_text>(text: S, x: c_int, y: c_int) -> Result { - Graphics::Default().draw_text(text, x, y) -} - -/// Draws the given `text` using the provided options. -/// -/// If no `font` has been set with [`set_font`], -/// the default system font `Asheville Sans 14 Light` is used. -/// -/// Same as [`draw_text`] but takes a [`sys::ffi::CStr`], -/// but little bit more efficient. -/// -/// This function is shorthand for [`Graphics::draw_text_cstr`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::drawText`]. -#[doc(alias = "sys::ffi::playdate_graphics::drawText")] -#[inline(always)] -pub fn draw_text_cstr(text: &CStr, encoding: StringEncoding, x: c_int, y: c_int) -> c_int { - Graphics::Default().draw_text_cstr(text, encoding, x, y) -} - -/// Draws the `text` in the given rectangle using the provided options. -/// -/// If no `font` has been set with [`set_font`], -/// the default system font `Asheville Sans 14 Light`` is used. -/// -/// This function is shorthand for [`Graphics::draw_text_in_rect`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::drawTextInRect`]. -#[doc(alias = "sys::ffi::playdate_graphics::drawText")] -#[inline(always)] -pub fn draw_text_in_rect>(text: S, - x: c_int, y: c_int, - width: c_int, height: c_int, - wrap: TextWrappingMode, - align: TextAlignment) -> Result<(), NulError> { - Graphics::Default().draw_text_in_rect(text, x, y, width, height, wrap, align) -} - -/// Returns the width of the given `text` in the given `font`. -/// -/// This function is shorthand for [`Graphics::get_text_width`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::getTextWidth`]. -#[doc(alias = "sys::ffi::playdate_graphics::getTextWidth")] -#[inline(always)] -pub fn get_text_width>(text: S, font: Option<&Font>, tracking: c_int) -> Result { - Graphics::Default().get_text_width(text, font, tracking) -} - -/// Returns the width of the given `text` in the given `font`. -/// -/// Same as [`get_text_width`] but takes a [`sys::ffi::CStr`], -/// but little bit more efficient. -/// -/// This function is shorthand for [`Graphics::get_text_width_cstr`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::getTextWidth`]. -#[doc(alias = "sys::ffi::playdate_graphics::getTextWidth")] -#[inline(always)] -pub fn get_text_width_cstr(text: &CStr, encoding: StringEncoding, font: Option<&Font>, tracking: c_int) -> c_int { - Graphics::Default().get_text_width_cstr(text, encoding, font, tracking) -} - - -/// Returns the height of the given `font`. -/// -/// This function is shorthand for [`Graphics::get_font_height`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::getFontHeight`]. -#[doc(alias = "sys::ffi::playdate_graphics::getFontHeight")] -#[inline(always)] -pub fn get_font_height(font: &Font) -> u8 { Graphics::Default().get_font_height(font) } - -/// Sets the `font` to use in subsequent [`draw_text`] calls. -/// -/// This function is shorthand for [`Graphics::set_font`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::setFont`]. -#[doc(alias = "sys::ffi::playdate_graphics::setFont")] -#[inline(always)] -pub fn set_font(font: &Font) { Graphics::Default().set_font(font) } - -/// Returns the kerning adjustment between characters `glyph_code` and `next_code` as specified by the font -/// -/// This function is shorthand for [`Graphics::get_glyph_kerning`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::getGlyphKerning`]. -#[doc(alias = "sys::ffi::playdate_graphics::getGlyphKerning")] -#[inline(always)] -pub fn get_glyph_kerning(glyph: &Glyph, glyph_code: u32, next_code: u32) -> c_int { - Graphics::Default().get_glyph_kerning(glyph, glyph_code, next_code) -} - -/// Returns an [`Glyph`] object for character `c` in [`FontPage`] page, -/// -/// To also get the glyph’s bitmap and `advance` value -/// use [`get_page_glyph_with_bitmap`] instead. -/// -/// This function is shorthand for [`Graphics::get_page_glyph`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::getPageGlyph`]. -#[doc(alias = "sys::ffi::playdate_graphics::getPageGlyph")] -#[inline(always)] -pub fn get_page_glyph(page: &FontPage, c: u32) -> Result { - Graphics::Default().get_page_glyph(page, c) -} - -/// Returns an [`Glyph`] object for character `c` in [`FontPage`] page, -/// and optionally returns the glyph’s bitmap and `advance` value. -/// -/// If bitmap is not needed, use [`get_page_glyph`] instead. -/// -/// This function is shorthand for [`Graphics::get_page_glyph_with_bitmap`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::getPageGlyph`]. -#[doc(alias = "sys::ffi::playdate_graphics::getPageGlyph")] -#[inline(always)] -pub fn get_page_glyph_with_bitmap<'p>(page: &'p FontPage, - c: u32, - advance: &mut c_int) - -> Result<(Glyph, BitmapRef<'p>), Error> { - Graphics::Default().get_page_glyph_with_bitmap(page, c, advance) -} - - -/// Returns an [`FontPage`] object for the given character code `c`. -/// -/// Each [`FontPage`] contains information for 256 characters; -/// specifically, if `(c1 & ~0xff) == (c2 & ~0xff)`, -/// then `c1` and `c2` belong to the same page and the same [`FontPage`] -/// can be used to fetch the character data for both instead of searching for the page twice. -/// -/// This function is shorthand for [`Graphics::get_font_page`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::getFontPage`]. -#[doc(alias = "sys::ffi::playdate_graphics::getFontPage")] -#[inline(always)] -pub fn get_font_page(font: &Font, c: u32) -> Result { - Graphics::Default().get_font_page(font, c) -} - - -/// Returns the [`Font`] object for the font file at `path`. -/// -/// This function is shorthand for [`Graphics::load_font`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::loadFont`]. -#[doc(alias = "sys::ffi::playdate_graphics::loadFont")] -#[inline(always)] -pub fn load_font>(path: P) -> Result { Graphics::Default().load_font(path) } - - -/// ⚠️ Caution: This function is not tested. -/// -/// Returns an [`Font`] object wrapping the LCDFontData data -/// comprising the contents (minus 16-byte header) of an uncompressed pft file. -/// -/// The `wide` corresponds to the flag in the header indicating -/// whether the font contains glyphs at codepoints above `U+1FFFF`. -/// -/// This function is shorthand for [`Graphics::make_font_from_bytes`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::makeFontFromData`]. -#[doc(alias = "sys::ffi::playdate_graphics::makeFontFromData")] -#[inline(always)] -pub fn make_font_from_bytes(data: &[u8], wide: c_int) -> Result { - Graphics::Default().make_font_from_bytes(data, wide) -} - - -/// Sets the leading adjustment (added to the leading specified in the font) to use when drawing text. -/// -/// This function is shorthand for [`Graphics::set_text_leading`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::setTextLeading`]. -#[doc(alias = "sys::ffi::playdate_graphics::setTextLeading")] -#[inline(always)] -pub fn set_text_leading(line_height_adjustment: c_int) { - Graphics::Default().set_text_leading(line_height_adjustment) -} - -/// Sets the tracking to use when drawing text. -/// -/// This function is shorthand for [`Graphics::set_text_tracking`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::setTextTracking`]. -#[doc(alias = "sys::ffi::playdate_graphics::setTextTracking")] -#[inline(always)] -pub fn set_text_tracking(tracking: c_int) { Graphics::Default().set_text_tracking(tracking) } - - -/// Gets the tracking used when drawing text. -/// -/// This function is shorthand for [`Graphics::set_text_tracking`], -/// using default ZST end-point. -/// -/// Equivalent to [`sys::ffi::playdate_graphics::getTextTracking`]. -#[doc(alias = "sys::ffi::playdate_graphics::getTextTracking")] -#[inline(always)] -pub fn get_text_tracking() -> c_int { Graphics::Default().get_text_tracking() } - - +#[gen_api_shorthands::gen_shorthands] impl Graphics { /// Draws the given `text` using the provided coords `x`, `y`. /// diff --git a/api/lua/Cargo.toml b/api/lua/Cargo.toml index 428f4f55..7835d6b0 100644 --- a/api/lua/Cargo.toml +++ b/api/lua/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "playdate-lua" -version = "0.1.4" +version = "0.1.5" readme = "README.md" description = "High-level Lua API built on-top of Playdate API" keywords = ["playdate", "sdk", "api", "gamedev"] @@ -23,6 +23,7 @@ bindings-derive-debug = ["sys/bindings-derive-debug"] [dependencies] +gen-api-shorthands.workspace = true sys = { workspace = true, default-features = false } [dev-dependencies] diff --git a/api/lua/src/lib.rs b/api/lua/src/lib.rs index 3a33d7c2..7c5d666c 100644 --- a/api/lua/src/lib.rs +++ b/api/lua/src/lib.rs @@ -51,6 +51,7 @@ impl Lua { impl Lua {} +#[gen_api_shorthands::gen_shorthands] impl Lua { /// Adds the Lua function *f* to the Lua runtime, with name *name*. (*name* /// can be a table path using dots, e.g. if name = “mycode.myDrawingFunction” diff --git a/api/scoreboards/Cargo.toml b/api/scoreboards/Cargo.toml index 07e542cf..3af7e10c 100644 --- a/api/scoreboards/Cargo.toml +++ b/api/scoreboards/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "playdate-scoreboards" -version = "0.1.6" +version = "0.1.7" readme = "README.md" description = "High-level Scoreboards API built on-top of Playdate API" keywords = ["playdate", "sdk", "api", "gamedev"] @@ -23,6 +23,7 @@ bindings-derive-debug = ["sys/bindings-derive-debug"] [dependencies] +gen-api-shorthands.workspace = true sys = { workspace = true, default-features = false } erased_set = "0.8" diff --git a/api/scoreboards/src/lib.rs b/api/scoreboards/src/lib.rs index 82f51ca2..f3ad4a37 100644 --- a/api/scoreboards/src/lib.rs +++ b/api/scoreboards/src/lib.rs @@ -63,6 +63,7 @@ impl Scoreboards { } +#[gen_api_shorthands::gen_shorthands] impl Scoreboards { /// Requests to add score `value` to the board with given `board_id`. /// diff --git a/api/sound/Cargo.toml b/api/sound/Cargo.toml index a3f00661..aa332dcb 100644 --- a/api/sound/Cargo.toml +++ b/api/sound/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "playdate-sound" -version = "0.4.4" +version = "0.4.5" readme = "README.md" description = "High-level sound API built on-top of Playdate API" keywords = ["playdate", "sdk", "api", "gamedev"] @@ -24,6 +24,7 @@ bindings-derive-debug = ["sys/bindings-derive-debug", "fs/bindings-derive-debug" [dependencies] +gen-api-shorthands.workspace = true sys = { workspace = true, default-features = false } fs = { workspace = true, default-features = false } diff --git a/api/sound/src/lib.rs b/api/sound/src/lib.rs index 2bad57c6..9206e530 100644 --- a/api/sound/src/lib.rs +++ b/api/sound/src/lib.rs @@ -58,6 +58,7 @@ impl Sound { pub fn new_with(api: Api) -> Self { Self(api) } } +#[gen_api_shorthands::gen_shorthands] impl Sound { /// Returns the sound engine’s current time value, in units of sample frames, `44100` per second. /// diff --git a/api/system/Cargo.toml b/api/system/Cargo.toml index 2282fd6a..d7086738 100644 --- a/api/system/Cargo.toml +++ b/api/system/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "playdate-system" -version = "0.3.15" +version = "0.3.16" readme = "README.md" description = "High-level System API built on-top of Playdate API" keywords = ["playdate", "sdk", "api", "gamedev"] @@ -22,11 +22,9 @@ bindgen-runtime = ["sys/bindgen-runtime"] bindgen-static = ["sys/bindgen-static"] bindings-derive-debug = ["sys/bindings-derive-debug"] - -[dependencies.sys] -workspace = true -default-features = false - +[dependencies] +gen-api-shorthands.workspace = true +sys = { workspace = true, default-features = false } [[example]] name = "handler-boxed" diff --git a/api/system/src/lib.rs b/api/system/src/lib.rs index c6c662d2..901489ef 100644 --- a/api/system/src/lib.rs +++ b/api/system/src/lib.rs @@ -65,7 +65,7 @@ impl System { } } - +#[gen_api_shorthands::gen_shorthands] impl System { /// Equivalent to [`sys::ffi::playdate_sys::getLanguage`] #[doc(alias = "sys::ffi::playdate_sys::getLanguage")] diff --git a/support/bindgen/Cargo.toml b/support/bindgen/Cargo.toml index d3110b32..c6e79101 100644 --- a/support/bindgen/Cargo.toml +++ b/support/bindgen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "playdate-bindgen" -version = "0.2.2" +version = "0.2.3" readme = "README.md" description = "Preconfigured Bindgen with extra codegen for Playdate C-API." keywords = ["playdate", "bindings", "ffi", "code-generation"] @@ -21,9 +21,9 @@ html5ever = { version = "0.27.0", optional = true } markup5ever_rcdom = { version = "0.3.0", optional = true } # doc-gen: -proc-macro2 = { version = "1.0", optional = true } -syn = { version = "2.0", optional = true } # +full, extra-traits, visit-mut -quote = { version = "1.0", optional = true } +proc-macro2 = { workspace = true, optional = true } +quote = { workspace = true, optional = true } +syn = { workspace = true, optional = true } log = { workspace = true, optional = true } prettyplease = { version = "0.2", optional = true, features = ["verbatim"] } diff --git a/support/gen-api-shorthands/Cargo.toml b/support/gen-api-shorthands/Cargo.toml new file mode 100644 index 00000000..539268b0 --- /dev/null +++ b/support/gen-api-shorthands/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "playdate-gen-api-shorthands" +version = "0.1.0" +keywords = ["playdate", "bindings", "code-generation"] +edition.workspace = true +license.workspace = true +authors = ["kana "] +homepage.workspace = true +repository.workspace = true + +[lib] +proc-macro = true + +[dependencies] +proc-macro2.workspace = true +quote.workspace = true +syn.workspace = true diff --git a/support/gen-api-shorthands/src/lib.rs b/support/gen-api-shorthands/src/lib.rs new file mode 100644 index 00000000..cad07ac9 --- /dev/null +++ b/support/gen-api-shorthands/src/lib.rs @@ -0,0 +1,124 @@ +use quote::quote; +use syn::{parse::Parse, parse_macro_input, spanned::Spanned, FnArg, Ident, ImplItem, ImplItemFn, ItemImpl, Token, Visibility}; + +#[proc_macro_attribute] +pub fn gen_shorthands(attr: proc_macro::TokenStream, item: proc_macro::TokenStream) -> proc_macro::TokenStream { + let source_impl: proc_macro2::TokenStream = item.clone().into(); + + let target_options = parse_macro_input!(attr as GenTargetOptions); + let (api, impl_items) = parse_api_impl(parse_macro_input!(item as ItemImpl)); + + let shorthands = impl_items.into_iter() + .map(parse_api_method) + .map(|method| api_method_into_shorthand(&api, method)) + .collect::>(); + + let shorthands = target_options.apply(quote! { #(#shorthands)* }); + + proc_macro::TokenStream::from(quote! { + #source_impl + #shorthands + }) +} + +enum GenTargetOptions { + InPlace, + GenMod { + mod_vis: Visibility, + mod_token: Token![mod], + mod_name: Ident, + } +} + +impl Parse for GenTargetOptions { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + if input.is_empty() { + return Ok(GenTargetOptions::InPlace); + } + + Ok(GenTargetOptions::GenMod { + mod_vis: input.parse()?, + mod_token: input.parse()?, + mod_name: input.parse()?, + }) + } +} + +impl GenTargetOptions { + fn apply(self, item: proc_macro2::TokenStream) -> proc_macro2::TokenStream { + match self { + GenTargetOptions::InPlace => item, + GenTargetOptions::GenMod { mod_vis, mod_token, mod_name } => { + quote! { + #mod_vis #mod_token #mod_name { + use super::*; + #item + } + } + } + } + } +} + +fn parse_api_impl(impl_: ItemImpl) -> (Ident, Vec) { + let api = match *impl_.self_ty { + syn::Type::Path(syn::TypePath { qself: None, path }) => path + .segments.last().expect("empty path") + .ident.clone(), + _ => panic!("only simple paths are supported"), + }; + + assert!(impl_.trait_.is_none(), "trait impls are not supported"); + + return (api, impl_.items); +} + +fn parse_api_method(item: ImplItem) -> ImplItemFn { + let ImplItem::Fn(method) = item else { panic!("only methods are supported"); }; + + assert!(method.defaultness.is_none(), "default methods are not supported"); + assert!(method.sig.constness.is_none(), "const methods are not supported"); + assert!(method.sig.asyncness.is_none(), "async methods are not supported"); + assert!(method.sig.unsafety.is_none(), "unsafe methods are not supported"); + assert!(method.sig.abi.is_none(), "extern methods are not supported"); + assert!(method.sig.variadic.is_none(), "variadic methods are not supported"); + assert!(matches!(method.sig.inputs.first(), Some(FnArg::Receiver(_))), "only methods are supported"); + + return method; +} + +fn api_method_into_shorthand(api: &Ident, mut method: ImplItemFn) -> ImplItemFn { + let method_name = method.sig.ident.clone(); + + // Remove the receiver from the method signature + method.sig.inputs = method.sig.inputs.into_iter().filter(|input| matches!(input, FnArg::Typed(_))).collect(); + + + // All shorthand functions are public + method.vis = Visibility::Public(Token![pub](method.span())); + + + // All shorthand functions should inline + method.attrs.append({ + let shorthand_doc_msg = format!("This function is shorthand for [`{}::{}`], using default ZST end-point.", api, method_name); + + &mut vec![ + syn::parse_quote! { #[doc = ""] }, + syn::parse_quote! { #[doc = #shorthand_doc_msg] }, + syn::parse_quote! { #[inline(always)] }, + ] + }); + + + // Just call the method from the default end-point + method.block = { + let args = method.sig.inputs.iter().filter_map(|input| match input { + FnArg::Receiver(_) => None, + FnArg::Typed(pat) => Some(&pat.pat), + }).collect::>(); + + syn::parse_quote! { { #api::Default().#method_name( #(#args),* ) } } + }; + + return method; +}