playdate_graphics/bitmap/
table.rs

1//! Playdate bitmap-table API
2
3use alloc::boxed::Box;
4use core::ffi::c_char;
5use core::ffi::c_int;
6
7use sys::ffi::CString;
8use sys::ffi::LCDBitmapTable;
9use fs::Path;
10
11use crate::error::ApiError;
12use crate::error::Error;
13use super::Bitmap;
14use super::api::Api as BitmapApi;
15
16
17#[cfg_attr(feature = "bindings-derive-debug", derive(Debug))]
18pub struct BitmapTable<Api: api::Api = api::Default, const FREE_ON_DROP: bool = true>(*mut LCDBitmapTable, Api);
19
20impl<Api: api::Api, const FOD: bool> Drop for BitmapTable<Api, FOD> {
21	fn drop(&mut self) {
22		if FOD && !self.0.is_null() {
23			let f = self.1.free_bitmap_table();
24			unsafe { f(self.0) };
25			self.0 = core::ptr::null_mut();
26		}
27	}
28}
29
30
31impl<Api: api::Api> BitmapTable<Api, true> {
32	/// Allocates and returns a new [`BitmapTable`] that can hold count `width` by `height` [`Bitmap`]s.
33	///
34	/// Equivalent to [`sys::ffi::playdate_graphics::newBitmapTable`].
35	#[doc(alias = "sys::ffi::playdate_graphics::newBitmapTable")]
36	pub fn new(count: c_int, width: c_int, height: c_int) -> Result<Self, Error>
37		where Api: Default {
38		let api = Api::default();
39		Self::new_with(api, count, width, height)
40	}
41
42	/// Allocates and returns a new [`BitmapTable`] that can hold count `width` by `height` [`Bitmap`]s,
43	/// using the given `api`.
44	///
45	/// Equivalent to [`sys::ffi::playdate_graphics::newBitmapTable`].
46	#[doc(alias = "sys::ffi::playdate_graphics::newBitmapTable")]
47	pub fn new_with(api: Api, count: c_int, width: c_int, height: c_int) -> Result<Self, Error> {
48		let f = api.new_bitmap_table();
49		let ptr = unsafe { f(count, width, height) };
50		if ptr.is_null() {
51			Err(Error::Alloc)
52		} else {
53			Ok(Self(ptr, api))
54		}
55	}
56
57
58	/// Allocates and returns a new [`BitmapTable`] from the file at `path`.
59	///
60	/// If there is no file at `path`, the function returns error.
61	///
62	/// Calls [`sys::ffi::playdate_graphics::loadBitmapTable`].
63	#[doc(alias = "sys::ffi::playdate_graphics::loadBitmapTable")]
64	pub fn load<P: AsRef<Path>>(path: P) -> Result<Self, ApiError>
65		where Api: Default {
66		let api = Api::default();
67		Self::load_with(api, path)
68	}
69
70	/// Allocates and returns a new [`BitmapTable`] from the file at `path`.
71	///
72	/// If there is no file at `path`, the function returns error.
73	///
74	/// Calls [`sys::ffi::playdate_graphics::loadBitmapTable`].
75	#[doc(alias = "sys::ffi::playdate_graphics::loadBitmapTable")]
76	pub fn load_with<P: AsRef<Path>>(api: Api, path: P) -> Result<Self, ApiError> {
77		let mut err = Box::new(core::ptr::null() as *const c_char);
78		let out_err = Box::into_raw(err);
79
80		let path = CString::new(path.as_ref())?;
81
82		let f = api.load_bitmap_table();
83		let ptr = unsafe { f(path.as_ptr() as *mut c_char, out_err as _) };
84		if ptr.is_null() {
85			err = unsafe { Box::from_raw(out_err) };
86			if let Some(err) = fs::error::Error::from_ptr(*err) {
87				Err(Error::Fs(err).into())
88			} else {
89				Err(Error::Alloc.into())
90			}
91		} else {
92			Ok(Self(ptr, api))
93		}
94	}
95}
96
97impl<Api: api::Api, const FOD: bool> BitmapTable<Api, FOD> {
98	/// Loads the image-table at `path` into the previously allocated this table.
99	///
100	/// Equivalent to [`sys::ffi::playdate_graphics::loadIntoBitmapTable`].
101	#[doc(alias = "sys::ffi::playdate_graphics::loadIntoBitmapTable")]
102	pub fn load_into<P: AsRef<Path>>(&mut self, path: P) -> Result<(), ApiError> {
103		let mut err = Box::new(core::ptr::null() as *const c_char);
104		let out_err = Box::into_raw(err);
105
106		let path = CString::new(path.as_ref())?;
107
108		let f = self.1.load_into_bitmap_table();
109		unsafe { f(path.as_ptr() as *mut c_char, self.0, out_err as _) };
110		err = unsafe { Box::from_raw(out_err) };
111		if let Some(err) = fs::error::Error::from_ptr(*err) {
112			Err(Error::Fs(err).into())
113		} else {
114			Ok(())
115		}
116	}
117
118
119	/// Returns the `index` bitmap in this table,
120	/// if `index` is out of bounds, the function returns `None`.
121	///
122	/// Creates new default api access-point.
123	///
124	/// Equivalent to [`sys::ffi::playdate_graphics::getTableBitmap`].
125	#[doc(alias = "sys::ffi::playdate_graphics::getTableBitmap")]
126	pub fn get<'table, BitApi: BitmapApi>(&'table self, index: c_int) -> Option<Bitmap<BitApi, true>>
127		where Bitmap<BitApi, true>: 'table,
128		      BitApi: Default {
129		self.get_with(BitApi::default(), index)
130	}
131
132	/// Returns the `index` bitmap in this table,
133	/// if `index` is out of bounds, the function returns `None`.
134	///
135	/// Produced `Bitmap` uses passed `api` access-point.
136	///
137	/// Equivalent to [`sys::ffi::playdate_graphics::getTableBitmap`].
138	#[doc(alias = "sys::ffi::playdate_graphics::getTableBitmap")]
139	pub fn get_with<'table, BitApi: BitmapApi>(&'table self,
140	                                           api: BitApi,
141	                                           index: c_int)
142	                                           -> Option<Bitmap<BitApi, true>>
143		where Bitmap<BitApi, true>: 'table
144	{
145		let f = self.1.get_table_bitmap();
146		let ptr = unsafe { f(self.0, index) };
147		if ptr.is_null() {
148			None
149		} else {
150			Some(Bitmap(ptr, api))
151		}
152	}
153
154	/// Returns the bitmap table’s image count in the `count` if not `None`
155	/// and number of cells across in the `width` (ditto) if not `None` .
156	///
157	/// Equivalent to [`sys::ffi::playdate_graphics::getTableBitmap`].
158	#[doc(alias = "sys::ffi::playdate_graphics::getTableBitmap")]
159	pub fn info<'table, BitApi: BitmapApi>(&'table self, count: Option<&mut c_int>, width: Option<&mut c_int>) {
160		let f = self.1.get_bitmap_table_info();
161		unsafe {
162			use core::ptr::null_mut;
163			f(
164			  self.0,
165			  count.map_or(null_mut() as _, |v| v as *mut _),
166			  width.map_or(null_mut() as _, |v| v as *mut _),
167			)
168		}
169	}
170}
171
172
173pub mod api {
174	use core::ffi::c_char;
175	use core::ffi::c_int;
176	use sys::ffi::LCDBitmap;
177	use sys::ffi::LCDBitmapTable;
178
179
180	/// Default graphics bitmap table api end-point, ZST.
181	///
182	/// All calls approximately costs ~3 derefs.
183	pub type Default = crate::api::Default;
184
185	/// Cached graphics bitmap table api end-point.
186	///
187	/// Stores one reference, so size on stack is eq `usize`.
188	///
189	/// All calls approximately costs ~1 deref.
190	pub type Cache = crate::api::Cache;
191
192
193	/// End-point with methods about ops over bitmap-table.
194	pub trait Api {
195		/// Equivalent to [`sys::ffi::playdate_graphics::newBitmapTable`]
196		#[doc(alias = "sys::ffi::playdate_graphics::newBitmapTable")]
197		fn new_bitmap_table(
198			&self)
199			-> unsafe extern "C" fn(count: c_int, width: c_int, height: c_int) -> *mut LCDBitmapTable {
200			*sys::api!(graphics.newBitmapTable)
201		}
202
203
204		/// Equivalent to [`sys::ffi::playdate_graphics::freeBitmapTable`]
205		#[doc(alias = "sys::ffi::playdate_graphics::freeBitmapTable")]
206		fn free_bitmap_table(&self) -> unsafe extern "C" fn(table: *mut LCDBitmapTable) {
207			*sys::api!(graphics.freeBitmapTable)
208		}
209
210
211		/// Equivalent to [`sys::ffi::playdate_graphics::loadBitmapTable`]
212		#[doc(alias = "sys::ffi::playdate_graphics::loadBitmapTable")]
213		fn load_bitmap_table(
214			&self)
215			-> unsafe extern "C" fn(path: *const c_char, out_err: *mut *const c_char) -> *mut LCDBitmapTable {
216			*sys::api!(graphics.loadBitmapTable)
217		}
218
219		/// Equivalent to [`sys::ffi::playdate_graphics::loadIntoBitmapTable`]
220		#[doc(alias = "sys::ffi::playdate_graphics::loadIntoBitmapTable")]
221		fn load_into_bitmap_table(
222			&self)
223			-> unsafe extern "C" fn(path: *const c_char, table: *mut LCDBitmapTable, out_err: *mut *const c_char) {
224			*sys::api!(graphics.loadIntoBitmapTable)
225		}
226
227		/// Equivalent to [`sys::ffi::playdate_graphics::getTableBitmap`]
228		#[doc(alias = "sys::ffi::playdate_graphics::getTableBitmap")]
229		fn get_table_bitmap(&self)
230		                    -> unsafe extern "C" fn(table: *mut LCDBitmapTable, idx: c_int) -> *mut LCDBitmap {
231			*sys::api!(graphics.getTableBitmap)
232		}
233
234		/// Equivalent to [`sys::ffi::playdate_graphics::getBitmapTableInfo`]
235		#[doc(alias = "sys::ffi::playdate_graphics::getBitmapTableInfo")]
236		fn get_bitmap_table_info(
237			&self)
238			-> unsafe extern "C" fn(table: *mut LCDBitmapTable, count: *mut c_int, width: *mut c_int) {
239			*sys::api!(graphics.getBitmapTableInfo)
240		}
241	}
242}