1use super::{
28 opaque_result_type, wrap_owned, DragValue, GestureMask, ViewHandle,
29};
30use crate::abi;
31use crate::resolve;
32use core::ffi::c_void;
33
34pub struct GestureValue<V: GestureData = ()> {
48 pub(crate) value: Vec<u8>,
49 pub(crate) meta: *const c_void,
50 pub(crate) value_meta: *const c_void,
52 marker: core::marker::PhantomData<fn(V)>,
54}
55
56pub trait GestureData: Copy + 'static {
65 unsafe fn read(at: *const u8) -> Self;
70}
71
72impl GestureData for () {
73 unsafe fn read(_: *const u8) -> Self {}
74}
75
76impl GestureData for bool {
77 unsafe fn read(at: *const u8) -> Self {
79 unsafe { *at != 0 }
80 }
81}
82
83impl GestureData for DragValue {
84 unsafe fn read(at: *const u8) -> Self {
85 unsafe { super::read_drag_value(at) }
86 }
87}
88
89impl GestureData for f64 {
90 unsafe fn read(at: *const u8) -> Self {
93 unsafe {
94 f64::from_le_bytes(
95 core::slice::from_raw_parts(at, 8).try_into().expect("8 bytes"),
96 )
97 }
98 }
99}
100
101impl<V: GestureData> GestureValue<V> {
102 fn wt(&self) -> *const c_void {
104 let wt = unsafe { abi::get_view_wt_for_proto(self.meta, resolve::gesture_proto()) };
105 assert!(!wt.is_null(), "{}: Gesture", crate::diag::type_name(self.meta));
106 wt
107 }
108}
109
110pub fn tap(count: i64) -> GestureValue<()> {
112 unsafe {
113 let meta = abi::metadata0(resolve::tap_gesture_ma());
114 assert!(!meta.is_null(), "TapGesture metadata");
115 let mut value = vec![0u8; abi::type_bytes(meta)];
116 core::arch::asm!("blr {f}", f = in(reg) resolve::tap_gesture_init(),
120 in("x0") count,
121 in("x8") value.as_mut_ptr(),
122 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
123 lateout("x5") _, lateout("x6") _, lateout("x7") _,
124 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
125 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
126 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
127 clobber_abi("C"),
128 );
129 GestureValue { value, meta, value_meta: core::ptr::null(), marker: core::marker::PhantomData }
132 }
133}
134
135pub fn long_press(duration: f64, max_distance: f64) -> GestureValue<bool> {
137 unsafe {
138 let meta = abi::metadata0(resolve::long_press_ma());
139 assert!(!meta.is_null(), "LongPressGesture metadata");
140 let mut value = vec![0u8; abi::type_bytes(meta)];
141 core::arch::asm!("blr {f}", f = in(reg) resolve::long_press_init(),
142 in("d0") duration, in("d1") max_distance,
143 in("x8") value.as_mut_ptr(),
144 in("x20") meta,
145 lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
146 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
147 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
148 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
149 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
150 );
151 let value_meta = abi::resolve_type_by_mangled_name(b"Sb");
154 GestureValue { value, meta, value_meta, marker: core::marker::PhantomData }
155 }
156}
157
158pub fn drag(minimum_distance: f64) -> GestureValue<DragValue> {
160 unsafe {
161 let meta = abi::metadata0(resolve::drag_gesture_ma());
162 assert!(!meta.is_null(), "DragGesture metadata");
163 let space_meta = abi::metadata0(resolve::local_space_ma());
164 let mut value = vec![0u8; abi::type_bytes(meta)];
165 let mut space = [0u8; 8];
169 core::arch::asm!("blr {f}", f = in(reg) resolve::drag_gesture_init(),
170 in("d0") minimum_distance,
171 in("x0") space.as_mut_ptr(),
172 in("x1") space_meta,
173 in("x2") resolve::local_space_wt(),
174 in("x8") value.as_mut_ptr(),
175 in("x20") meta,
176 lateout("x3") _, lateout("x4") _, lateout("x5") _, lateout("x6") _,
177 lateout("x7") _, lateout("x9") _, lateout("x10") _, lateout("x11") _,
178 lateout("x12") _, lateout("x13") _, lateout("x14") _, lateout("x15") _,
179 lateout("x16") _, lateout("x17") _, lateout("lr") _, lateout("x21") _,
180 clobber_abi("C"),
181 );
182 let value_meta = abi::metadata0(resolve::drag_value_ma());
183 GestureValue { value, meta, value_meta, marker: core::marker::PhantomData }
184 }
185}
186
187pub fn magnify(minimum_scale_delta: f64) -> GestureValue<f64> {
189 unsafe {
190 let meta = abi::metadata0(resolve::magnify_gesture_ma());
191 assert!(!meta.is_null(), "MagnifyGesture metadata");
192 let mut value = vec![0u8; abi::type_bytes(meta)];
193 core::arch::asm!("blr {f}", f = in(reg) resolve::magnify_gesture_init(),
194 in("d0") minimum_scale_delta,
195 in("x8") value.as_mut_ptr(),
196 in("x20") meta,
197 lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
198 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
199 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
200 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
201 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
202 );
203 let value_meta = abi::metadata0(resolve::magnify_value_ma());
204 GestureValue { value, meta, value_meta, marker: core::marker::PhantomData }
205 }
206}
207
208pub fn rotate(minimum_degrees: f64) -> GestureValue<f64> {
213 unsafe {
214 let meta = abi::metadata0(resolve::rotate_gesture_ma());
215 assert!(!meta.is_null(), "RotateGesture metadata");
216 let mut value = vec![0u8; abi::type_bytes(meta)];
217 let radians = minimum_degrees * core::f64::consts::PI / 180.0;
218 core::arch::asm!("blr {f}", f = in(reg) resolve::rotate_gesture_init(),
219 in("d0") radians,
220 in("x8") value.as_mut_ptr(),
221 in("x20") meta,
222 lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
223 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
224 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
225 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
226 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
227 );
228 let value_meta = abi::metadata0(resolve::rotate_value_ma());
229 GestureValue { value, meta, value_meta, marker: core::marker::PhantomData }
230 }
231}
232
233unsafe extern "C" fn invoke_handler<V: GestureData>(value: *const u8, payload: *mut c_void) {
243 let f = unsafe { &*(payload as *const Box<dyn Fn(V)>) };
244 f(unsafe { V::read(value) });
245}
246
247fn leak_handler<V: GestureData>(action: impl Fn(V) + 'static) -> *mut c_void {
249 let boxed: Box<dyn Fn(V)> = Box::new(action);
250 Box::into_raw(Box::new(boxed)) as *mut c_void
251}
252
253impl<V: GestureData> GestureValue<V> {
254 pub fn on_ended(self, action: impl Fn(V) + 'static) -> GestureValue<V> {
259 unsafe {
260 let g_wt = self.wt();
261 let ended_meta = abi::generic_metadata2(
262 resolve::ended_gesture_ma(),
263 self.meta,
264 g_wt,
265 );
266 assert!(!ended_meta.is_null(), "_EndedGesture metadata");
267 let mut out = vec![0u8; abi::type_bytes(ended_meta)];
268
269 let ctx = Box::leak(Box::new(abi::ValueClosureCtx::new(
270 invoke_handler::<V>,
271 leak_handler(action),
272 ))) as *mut abi::ValueClosureCtx;
273
274 let mut this = self.value;
275 core::arch::asm!("blr {f}", f = in(reg) resolve::gesture_on_ended(),
278 in("x0") abi::value_closure_thunk as *const () as u64,
279 in("x1") ctx as u64,
280 in("x2") self.meta,
281 in("x3") g_wt,
282 in("x8") out.as_mut_ptr(),
283 in("x20") this.as_mut_ptr(),
284 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
285 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
286 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
287 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
288 );
289 GestureValue {
292 value: out,
293 meta: ended_meta,
294 value_meta: self.value_meta,
295 marker: core::marker::PhantomData,
296 }
297 }
298 }
299
300 pub fn on_changed(self, action: impl Fn(V) + 'static) -> GestureValue<V> {
308 assert!(
309 !self.value_meta.is_null(),
310 "onChanged needs an Equatable Value; TapGesture's is Void — use on_ended"
311 );
312 unsafe {
313 let g_wt = self.wt();
314 let eq_wt = abi::get_view_wt_for_proto(self.value_meta, resolve::equatable_proto());
315 assert!(!eq_wt.is_null(), "gesture Value: Equatable");
316
317 let changed_meta = abi::generic_metadata_from_descriptor(
322 resolve::changed_gesture_desc(),
323 &[self.meta, g_wt, eq_wt],
324 );
325 assert!(!changed_meta.is_null(), "_ChangedGesture metadata");
326 let mut out = vec![0u8; abi::type_bytes(changed_meta)];
327
328 let ctx = Box::leak(Box::new(abi::ValueClosureCtx::new(
329 invoke_handler::<V>,
330 leak_handler(action),
331 ))) as *mut abi::ValueClosureCtx;
332
333 let mut this = self.value;
334 core::arch::asm!("blr {f}", f = in(reg) resolve::gesture_on_changed(),
337 in("x0") abi::value_closure_thunk as *const () as u64,
338 in("x1") ctx as u64,
339 in("x2") self.meta,
340 in("x3") g_wt,
341 in("x4") eq_wt,
342 in("x8") out.as_mut_ptr(),
343 in("x20") this.as_mut_ptr(),
344 lateout("x5") _, lateout("x6") _, lateout("x7") _,
345 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
346 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
347 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
348 );
349 GestureValue {
350 value: out,
351 meta: changed_meta,
352 value_meta: self.value_meta,
353 marker: core::marker::PhantomData,
354 }
355 }
356 }
357}
358
359impl<V: GestureData> GestureValue<V> {
360 pub fn sequenced<W: GestureData>(self, other: GestureValue<W>) -> GestureValue<()> {
365 unsafe {
366 combine(
367 self,
368 other,
369 resolve::gesture_sequenced(),
370 resolve::sequence_gesture_desc(),
371 )
372 }
373 }
374
375 pub fn exclusively<W: GestureData>(self, other: GestureValue<W>) -> GestureValue<()> {
377 unsafe {
378 combine(
379 self,
380 other,
381 resolve::gesture_exclusively(),
382 resolve::exclusive_gesture_desc(),
383 )
384 }
385 }
386
387 pub fn simultaneously<W: GestureData>(self, other: GestureValue<W>) -> GestureValue<()> {
389 unsafe {
390 combine(
391 self,
392 other,
393 resolve::gesture_simultaneously(),
394 resolve::simultaneous_gesture_desc(),
395 )
396 }
397 }
398}
399
400unsafe fn combine<A: GestureData, B: GestureData>(
411 first: GestureValue<A>,
412 second: GestureValue<B>,
413 f: *const c_void,
414 desc: *const c_void,
415) -> GestureValue<()> {
416 unsafe {
417 let a_wt = first.wt();
418 let b_wt = second.wt();
419 let meta = abi::generic_metadata_from_descriptor(
420 desc,
421 &[first.meta, second.meta, a_wt, b_wt],
422 );
423 assert!(!meta.is_null(), "combined gesture metadata");
424 let mut out = vec![0u8; abi::type_bytes(meta)];
425 let mut lhs = first.value;
426 let mut rhs = second.value;
427 core::arch::asm!("blr {f}", f = in(reg) f,
428 in("x0") rhs.as_mut_ptr(),
429 in("x1") first.meta,
430 in("x2") second.meta,
431 in("x3") a_wt,
432 in("x4") b_wt,
433 in("x8") out.as_mut_ptr(),
434 in("x20") lhs.as_mut_ptr(),
435 lateout("x5") _, lateout("x6") _, lateout("x7") _,
436 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
437 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
438 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
439 );
440 GestureValue {
447 value: out,
448 meta,
449 value_meta: core::ptr::null(),
450 marker: core::marker::PhantomData,
451 }
452 }
453}
454
455unsafe fn attach<V: GestureData>(
464 view: &ViewHandle,
465 g: &GestureValue<V>,
466 mask: GestureMask,
467 f: *const c_void,
468 oret: *const c_void,
469) -> ViewHandle {
470 unsafe {
471 let g_wt = g.wt();
472 let subst = [view.meta, g.meta, view.wt, g_wt];
473 let (meta, wt, size) = opaque_result_type(oret, &subst);
474 let mut result = vec![0u8; size];
475 let this = view.value_ptr();
476 let raw = mask_raw(mask);
479 let mut value = g.value.clone();
480 core::arch::asm!("blr {f}", f = in(reg) f,
481 in("x0") value.as_mut_ptr(),
482 in("x1") raw,
483 in("x2") view.meta,
484 in("x3") g.meta,
485 in("x4") view.wt,
486 in("x5") g_wt,
487 in("x8") result.as_mut_ptr(),
488 in("x20") this,
489 lateout("x6") _, lateout("x7") _,
490 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
491 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
492 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
493 );
494 wrap_owned(result, meta, wt)
495 }
496}
497
498fn mask_raw(mask: GestureMask) -> u64 {
502 unsafe {
503 let meta = abi::metadata0(resolve::gesture_mask_ma());
504 assert!(!meta.is_null(), "GestureMask metadata");
505 super::static_getter(mask.resolved(), meta).0
506 }
507}
508
509pub fn gesture<V: GestureData>(
511 view: &ViewHandle,
512 g: &GestureValue<V>,
513 mask: GestureMask,
514) -> ViewHandle {
515 unsafe { attach(view, g, mask, resolve::gesture_fn(), resolve::gesture_oret()) }
516}
517
518pub fn high_priority_gesture_of<V: GestureData>(
520 view: &ViewHandle,
521 g: &GestureValue<V>,
522 mask: GestureMask,
523) -> ViewHandle {
524 unsafe {
525 attach(
526 view,
527 g,
528 mask,
529 resolve::high_priority_gesture_fn(),
530 resolve::high_priority_gesture_oret(),
531 )
532 }
533}
534
535pub fn simultaneous_gesture_of<V: GestureData>(
537 view: &ViewHandle,
538 g: &GestureValue<V>,
539 mask: GestureMask,
540) -> ViewHandle {
541 unsafe {
542 attach(
543 view,
544 g,
545 mask,
546 resolve::simultaneous_gesture_fn(),
547 resolve::simultaneous_gesture_oret(),
548 )
549 }
550}