playdate_sprite/callback/
draw.rs

1use core::marker::PhantomData;
2use core::ops::Deref;
3
4use sys::ffi::{LCDSprite, PDRect};
5use sys::traits::AsRaw;
6
7use crate::{Sprite, SpriteApi, TypedSprite, SpriteRef, AnySprite, SharedSprite, SpriteType};
8use crate::api::{self, Api};
9
10
11// This is mostly probably should be implemented for OwnedSprite only.
12impl<UD, Api: api::Api, const FOD: bool> Sprite<UD, Api, FOD> {
13	/// Sets the draw function for the this sprite.
14	///
15	/// ⚠️ Caution:
16	/// Do not forget to set [`bounds`](Sprite::set_bounds) __before__ setting draw function,
17	/// default zero bounds causes UB in the system.
18	pub fn into_draw_handler<T: SpriteDraw<Userdata = UD>>(self) -> Handle<FOD, Self, T>
19		where T::Api: Default {
20		Handle::new(self)
21	}
22}
23
24
25pub trait SpriteDraw: Sized + SpriteType {
26	fn on_draw(sprite: &Handle<false, SharedSprite<Self::Userdata, Self::Api>, Self>,
27	           bounds: PDRect,
28	           draw_rect: PDRect);
29
30	unsafe extern "C" fn proxy(sprite: *mut LCDSprite, bounds: PDRect, draw_rect: PDRect)
31		where Self::Api: Default {
32		Self::on_draw(
33		              &Handle::new_unchanged(SpriteRef::from(sprite).into()),
34		              bounds,
35		              draw_rect,
36		)
37	}
38}
39
40
41pub struct Handle<const FOD: bool, T, H>(pub(super) T, PhantomData<H>)
42	where T: TypedSprite + Sized,
43	      H: SpriteDraw;
44
45impl<const FOD: bool, T, H> AnySprite for Handle<FOD, T, H>
46	where T: TypedSprite + Sized,
47	      H: SpriteDraw,
48	      T: AnySprite
49{
50}
51impl<const FOD: bool, T, H> SpriteApi for Handle<FOD, T, H>
52	where T: TypedSprite + Sized,
53	      H: SpriteDraw,
54	      T: SpriteApi
55{
56	type Api = <T as SpriteApi>::Api;
57
58	fn api(&self) -> Self::Api
59		where Self::Api: Copy {
60		self.0.api()
61	}
62
63	fn api_ref(&self) -> &Self::Api { self.0.api_ref() }
64}
65
66impl<const FOD: bool, T, H> AsRaw for Handle<FOD, T, H>
67	where T: TypedSprite + Sized,
68	      H: SpriteDraw,
69	      T: AsRaw
70{
71	type Type = <T as AsRaw>::Type;
72	unsafe fn as_raw(&self) -> *mut Self::Type { self.0.as_raw() }
73}
74
75impl<const FOD: bool, T, H> Handle<FOD, T, H>
76	where T: TypedSprite + Sized,
77	      H: SpriteDraw
78{
79	/// - Unregister inner callback for sprite
80	/// - Unwrap, return the underlying sprite
81	/// - Remove the draw handler
82	#[must_use = "Sprite"]
83	pub fn into_inner(self) -> T {
84		let ptr = unsafe { self.0.as_raw() };
85		let f = self.0.api_ref().set_draw_function();
86		unsafe { f(ptr, None) };
87		self.0
88	}
89}
90
91
92impl<const FOD: bool, T, H> AsRef<Sprite<T::Userdata, T::Api, FOD>> for Handle<FOD, T, H>
93	where T: TypedSprite + AsRef<Sprite<T::Userdata, T::Api, FOD>>,
94	      H: SpriteDraw
95{
96	fn as_ref(&self) -> &Sprite<T::Userdata, T::Api, FOD> { self.0.as_ref() }
97}
98
99
100impl<const FOD: bool, T, H> AsMut<Sprite<T::Userdata, T::Api, FOD>> for Handle<FOD, T, H>
101	where T: TypedSprite + AsMut<Sprite<T::Userdata, T::Api, FOD>>,
102	      H: SpriteDraw
103{
104	fn as_mut(&mut self) -> &mut Sprite<T::Userdata, T::Api, FOD> { self.0.as_mut() }
105}
106
107
108impl<const FOD: bool, T, H> Deref for Handle<FOD, T, H>
109	where T: TypedSprite + AsRef<Sprite<T::Userdata, T::Api, FOD>>,
110	      H: SpriteDraw
111{
112	type Target = Sprite<T::Userdata, T::Api, FOD>;
113	fn deref(&self) -> &Self::Target { self.0.as_ref() }
114}
115
116
117impl<const FOD: bool, T, H> Handle<FOD, T, H>
118	where T: TypedSprite + SpriteApi,
119	      H: SpriteDraw
120{
121	pub(super) fn new(sprite: T) -> Self
122		where H::Api: Default {
123		let f = sprite.api_ref().set_draw_function();
124		unsafe { f(sprite.as_raw(), Some(H::proxy)) };
125		Self::new_unchanged(sprite)
126	}
127
128	fn new_unchanged(sprite: T) -> Self { Self(sprite, PhantomData::<H>) }
129}
130
131
132pub mod l2 {
133	use core::ops::Deref;
134	use core::marker::PhantomData;
135
136	use sys::traits::AsRaw;
137
138	use crate::AnySprite;
139	use crate::Sprite;
140	use crate::SpriteApi;
141	use crate::TypedSprite;
142	use crate::api;
143	use crate::callback::update;
144	use crate::callback::collision;
145
146	use super::SpriteDraw;
147
148
149	impl<UD, Api, const FOD: bool, H> update::Handle<FOD, Sprite<UD, Api, FOD>, H>
150		where Api: api::Api,
151		      H: update::SpriteUpdate
152	{
153		/// Sets the draw function for the this sprite.
154		///
155		/// ⚠️ Caution:
156		/// Do not forget to set [`bounds`](Sprite::set_bounds) __before__ setting draw function,
157		/// default zero bounds causes UB in the system.
158		pub fn into_draw_handler<T: SpriteDraw<Userdata = UD>>(self) -> Handle<FOD, Sprite<UD, Api, FOD>, Self, T>
159			where T::Api: Default {
160			Handle::new(self)
161		}
162	}
163
164	impl<UD, Api, const FOD: bool, H> collision::Handle<FOD, Sprite<UD, Api, FOD>, H>
165		where Api: api::Api,
166		      H: collision::SpriteCollisionResponse
167	{
168		/// Sets the draw function for the this sprite.
169		///
170		/// ⚠️ Caution:
171		/// Do not forget to set [`bounds`](Sprite::set_bounds) __before__ setting draw function,
172		/// default zero bounds causes UB in the system.
173		pub fn into_draw_handler<T: SpriteDraw<Userdata = UD>>(self) -> Handle<FOD, Sprite<UD, Api, FOD>, Self, T>
174			where T::Api: Default {
175			Handle::new(self)
176		}
177	}
178
179	impl<UD, Api, const FOD: bool, H, H0>
180		collision::l2::Handle<FOD, Sprite<UD, Api, FOD>, update::Handle<FOD, Sprite<UD, Api, FOD>, H0>, H>
181		where Api: api::Api,
182		      H: collision::SpriteCollisionResponse,
183		      H0: update::SpriteUpdate
184	{
185		/// Sets the draw function for the this sprite.
186		///
187		/// ⚠️ Caution:
188		/// Do not forget to set [`bounds`](Sprite::set_bounds) __before__ setting draw function,
189		/// default zero bounds causes UB in the system.
190		pub fn into_draw_handler<T: SpriteDraw<Userdata = UD>>(self) -> Handle<FOD, Sprite<UD, Api, FOD>, Self, T>
191			where T::Api: Default {
192			Handle::new(self)
193		}
194	}
195
196	impl<UD, Api, const FOD: bool, H, H0>
197		update::l2::Handle<FOD, Sprite<UD, Api, FOD>, collision::Handle<FOD, Sprite<UD, Api, FOD>, H0>, H>
198		where Api: api::Api,
199		      H: update::SpriteUpdate,
200		      H0: collision::SpriteCollisionResponse
201	{
202		/// Sets the draw function for the this sprite.
203		///
204		/// ⚠️ Caution:
205		/// Do not forget to set [`bounds`](Sprite::set_bounds) __before__ setting draw function,
206		/// default zero bounds causes UB in the system.
207		pub fn into_draw_handler<T: SpriteDraw<Userdata = UD>>(self) -> Handle<FOD, Sprite<UD, Api, FOD>, Self, T>
208			where T::Api: Default {
209			Handle::new(self)
210		}
211	}
212
213
214	pub struct Handle<const FOD: bool, Sp, T, H>(pub(super) T, PhantomData<Sp>, PhantomData<H>)
215		where T: Sized,
216		      Sp: TypedSprite,
217		      H: SpriteDraw;
218
219
220	impl<const FOD: bool, Sp, T, H> AnySprite for Handle<FOD, Sp, T, H>
221		where Sp: TypedSprite,
222		      T: AnySprite,
223		      H: SpriteDraw
224	{
225	}
226	impl<const FOD: bool, Sp, T, H> SpriteApi for Handle<FOD, Sp, T, H>
227		where Sp: TypedSprite,
228		      T: SpriteApi,
229		      H: SpriteDraw
230	{
231		type Api = <T as SpriteApi>::Api;
232
233		fn api(&self) -> Self::Api
234			where Self::Api: Copy {
235			self.0.api()
236		}
237
238		fn api_ref(&self) -> &Self::Api { self.0.api_ref() }
239	}
240
241	impl<const FOD: bool, Sp, T, H> AsRaw for Handle<FOD, Sp, T, H>
242		where Sp: TypedSprite,
243		      T: AsRaw,
244		      H: SpriteDraw
245	{
246		type Type = <T as AsRaw>::Type;
247		unsafe fn as_raw(&self) -> *mut Self::Type { self.0.as_raw() }
248	}
249
250
251	impl<const FOD: bool, Sp, T, H> Handle<FOD, Sp, T, H>
252		where T: AsRef<Sp>,
253		      Sp: TypedSprite,
254		      H: SpriteDraw
255	{
256		/// - Unregister inner callback for sprite
257		/// - Unwrap, return the underlying sprite
258		/// - Remove the collision response handler
259		#[must_use = "Sprite"]
260		pub fn into_inner(self) -> T {
261			use crate::api::Api;
262
263			let ptr = unsafe { self.0.as_ref().as_raw() };
264			let f = self.0.as_ref().api_ref().set_draw_function();
265			unsafe { f(ptr, None) };
266			self.0
267		}
268	}
269
270
271	impl<const FOD: bool, Sp, T, H> AsRef<Sprite<Sp::Userdata, Sp::Api, FOD>> for Handle<FOD, Sp, T, H>
272		where T: AsRef<Sprite<Sp::Userdata, Sp::Api, FOD>>,
273		      Sp: TypedSprite,
274		      H: SpriteDraw
275	{
276		fn as_ref(&self) -> &Sprite<Sp::Userdata, Sp::Api, FOD> { self.0.as_ref() }
277	}
278
279
280	impl<const FOD: bool, Sp, T, H> Deref for Handle<FOD, Sp, T, H>
281		where T: AsRef<Sprite<Sp::Userdata, Sp::Api, FOD>>,
282		      Sp: TypedSprite,
283		      H: SpriteDraw
284	{
285		type Target = Sprite<Sp::Userdata, Sp::Api, FOD>;
286		fn deref(&self) -> &Self::Target { self.0.as_ref() }
287	}
288
289
290	impl<const FOD: bool, Sp, T, H> Handle<FOD, Sp, T, H>
291		where T: AsRef<Sp>,
292		      Sp: TypedSprite + SpriteApi,
293		      H: SpriteDraw
294	{
295		pub(super) fn new(sprite: T) -> Self
296			where H::Api: Default {
297			use crate::api::Api;
298
299			let f = sprite.as_ref().api_ref().set_draw_function();
300			unsafe { f(sprite.as_ref().as_raw(), Some(H::proxy)) };
301			Self::new_unchanged(sprite)
302		}
303
304		fn new_unchanged(sprite: T) -> Self { Self(sprite, PhantomData::<Sp>, PhantomData::<H>) }
305	}
306}