swiftui_native/views/
timeline.rs1use super::*;
4use crate::abi;
5use crate::resolve;
6use core::ffi::c_void;
7use crate::mangle;
8
9mangle::result_types! {
12 pub(crate) TIMELINE_T = ty("TimelineView").of(vec![ty("AnimationTimelineSchedule"), ty("AnyView")]);
15}
16
17pub(crate) type TimelineBuilder = Box<dyn Fn() -> ViewHandle>;
19
20pub(crate) unsafe extern "C" fn emit_timeline_view(out: *mut u8, _context: i64, payload: *mut c_void) {
23 let typed = unsafe { &*(payload as *const TypedTimelineBuilder) };
24 let view = (typed.builder)();
25 unsafe {
26 if typed.meta.is_null() {
27 *(out as *mut u64) = view.into_anyview_word();
28 return;
29 }
30 assert_eq!(
34 view.meta, typed.meta,
35 "a TimelineView builder returned {} after returning {} — it has to be \
36 one type. Use `view_if!` for a branch.",
37 crate::diag::type_name(view.meta),
38 crate::diag::type_name(typed.meta),
39 );
40 let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(view.meta);
41 if vwt.size > 0 {
42 (vwt.initialize_with_copy)(out as *mut c_void, view.value_ptr() as *mut c_void, view.meta);
43 }
44 }
45}
46
47pub(crate) struct TypedTimelineBuilder {
49 pub(crate) builder: TimelineBuilder,
50 pub(crate) meta: *const c_void,
51}
52
53pub fn timeline(builder: impl Fn() -> ViewHandle + 'static) -> ViewHandle {
73 unsafe {
74 let boxed: TimelineBuilder = Box::new(builder);
75 let probe = boxed();
79 let (probe_meta, probe_wt) = (probe.meta, probe.wt);
80 drop(probe);
81 let payload =
82 Box::into_raw(Box::new(TypedTimelineBuilder { builder: boxed, meta: core::ptr::null() }))
83 as *mut c_void;
84 let ctx = Box::leak(Box::new(abi::IndexClosureCtx::new(emit_timeline_view, payload)))
85 as *mut abi::IndexClosureCtx;
86
87 let sched_meta = abi::metadata0(resolve::anim_schedule_ma());
91 let mut schedule =
92 vec![0u8; abi::type_bytes(sched_meta)];
93 core::arch::asm!("blr {f}", f = in(reg) resolve::anim_schedule_init(),
94 in("x0") 0u64, in("x1") 1u64, in("x2") 0u64,
95 in("x8") schedule.as_mut_ptr(),
96 in("x20") sched_meta,
97 lateout("x3") _, lateout("x4") _, lateout("x5") _, lateout("x6") _,
98 lateout("x7") _, lateout("x9") _, lateout("x10") _, lateout("x11") _,
99 lateout("x12") _, lateout("x13") _, lateout("x14") _, lateout("x15") _,
100 lateout("x16") _, lateout("x17") _, lateout("lr") _, lateout("x21") _,
101 clobber_abi("C"),
102 );
103
104 let sched_wt =
105 abi::get_view_wt_for_proto(sched_meta, resolve::timeline_schedule_proto());
106 assert!(!sched_wt.is_null(), "AnimationTimelineSchedule: TimelineSchedule");
107
108 let (known_meta, known_wt, known_size) = result_type(&TIMELINE_T);
109 let typed = super::substitute_content(known_meta, 4, 1, 3, probe_meta, probe_wt);
112 let (meta, wt) = typed.unwrap_or((known_meta, known_wt));
113 let size = if typed.is_some() { abi::type_bytes(meta) } else { known_size };
114 let (content_meta, content_wt) = match typed {
115 Some(_) => (probe_meta, probe_wt),
116 None => (resolve::anyview_meta(), resolve::anyview_wt()),
117 };
118 (*(payload as *mut TypedTimelineBuilder)).meta =
120 if typed.is_some() { probe_meta } else { core::ptr::null() };
121 let mut result = vec![0u8; size];
122 core::arch::asm!("blr {f}", f = in(reg) resolve::timeline_init(),
127 in("x0") schedule.as_mut_ptr(),
128 in("x1") abi::index_closure_thunk as *const c_void,
129 in("x2") ctx,
130 in("x3") sched_meta,
131 in("x4") content_meta,
132 in("x5") sched_wt,
133 in("x6") content_wt,
134 in("x8") result.as_mut_ptr(),
135 lateout("x7") _,
136 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
137 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
138 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
139 clobber_abi("C"),
140 );
141 wrap_owned(result, meta, wt)
142 }
143}