1use crate::abi;
56use crate::resolve;
57use crate::views::ViewHandle;
58use core::ffi::c_void;
59use crate::mangle;
60
61type BodyBuilder = Box<dyn Fn(i64) -> ViewHandle + Send>;
65
66struct Instance {
68 builder: BodyBuilder,
69 binding: Option<Vec<u8>>,
72}
73
74static INSTANCES: std::sync::Mutex<Option<std::collections::HashMap<i64, Instance>>> =
81 std::sync::Mutex::new(None);
82static NEXT_ID: std::sync::atomic::AtomicI64 = std::sync::atomic::AtomicI64::new(1);
83
84fn with_instances<R>(f: impl FnOnce(&mut std::collections::HashMap<i64, Instance>) -> R) -> R {
85 let mut guard = INSTANCES.lock().expect("instance registry poisoned");
86 f(guard.get_or_insert_with(std::collections::HashMap::new))
87}
88
89core::arch::global_asm!(
91 ".p2align 2",
92 ".globl _rswift_view_body_thunk",
93 "_rswift_view_body_thunk:",
94 "mov x1, x20",
95 "mov x0, x8",
96 "b _rswift_view_body_getter",
97);
98
99unsafe extern "C" {
100 #[link_name = "rswift_view_body_thunk"]
101 fn view_body_thunk();
102}
103
104#[unsafe(no_mangle)]
106unsafe extern "C" fn rswift_view_body_getter(out: *mut u8, this: *const u8) {
107 unsafe {
108 let id = *(this.add(ID_OFFSET) as *const i64);
110
111 let value = if *(this.add(8) as *const u64) == 0 {
114 0
115 } else {
116 state_wrapped_value(this)
117 };
118
119 let binding = state_projected_binding(this);
122 let view = with_instances(|map| {
123 let inst = map.get_mut(&id)?;
124 if inst.binding.is_none() {
125 inst.binding = Some(binding);
126 }
127 Some((inst.builder)(value))
128 });
129
130 let view = view.unwrap_or_else(crate::views::empty_view);
131 *(out as *mut u64) = view.into_anyview_word();
132 }
133}
134
135unsafe fn state_wrapped_value(state: *const u8) -> i64 {
137 let mut out: i64 = 0;
138 unsafe {
139 core::arch::asm!("blr {f}", f = in(reg) resolve::state_wrapped_get(),
140 in("x8") &mut out as *mut i64,
141 in("x20") state,
142 in("x0") abi::generic_metadata1(resolve::state_ma(), resolve::int_meta()),
145 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
146 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
147 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
148 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
149 lateout("lr") _, lateout("x21") _, clobber_abi("C"),
150 );
151 }
152 out
153}
154
155unsafe fn state_projected_binding(state: *const u8) -> Vec<u8> {
157 unsafe {
158 let meta = abi::resolve_type_by_mangled_name(mangle::bound("7SwiftUI7BindingV", &[mangle::INT]).as_bytes());
159 assert!(!meta.is_null(), "Binding<Int> metadata");
160 let mut out = vec![0u8; abi::type_bytes(meta)];
161 core::arch::asm!("blr {f}", f = in(reg) resolve::state_projected_get(),
162 in("x8") out.as_mut_ptr(),
163 in("x20") state,
164 in("x0") abi::generic_metadata1(resolve::state_ma(), resolve::int_meta()),
165 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
166 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
167 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
168 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
169 lateout("lr") _, lateout("x21") _, clobber_abi("C"),
170 );
171 out
172 }
173}
174
175pub fn set_state(id: i64, value: i64) -> bool {
180 let binding = with_instances(|map| map.get(&id).and_then(|i| i.binding.clone()));
181 let Some(mut binding) = binding else { return false };
182 unsafe {
183 let meta = abi::resolve_type_by_mangled_name(mangle::bound("7SwiftUI7BindingV", &[mangle::INT]).as_bytes());
184 let mut v = value;
185 core::arch::asm!("blr {f}", f = in(reg) resolve::binding_wrapped_set(),
186 in("x0") &mut v as *mut i64,
187 in("x1") meta,
188 in("x20") binding.as_mut_ptr(),
189 lateout("x2") _, lateout("x3") _, lateout("x4") _, lateout("x5") _,
190 lateout("x6") _, lateout("x7") _, lateout("x8") _, lateout("x9") _,
191 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
192 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
193 lateout("lr") _, lateout("x21") _, clobber_abi("C"),
194 );
195 }
196 true
197}
198
199pub struct StatefulView {
221 pub metadata: *const c_void,
223 pub witness_table: *const c_void,
225 value: Vec<u8>,
227 pub id: i64,
229}
230
231impl StatefulView {
232 pub fn new(initial: i64, builder: impl Fn(i64) -> ViewHandle + Send + 'static) -> Self {
243 unsafe {
244 let id = NEXT_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
245 with_instances(|map| {
246 map.insert(id, Instance { builder: Box::new(builder), binding: None })
247 });
248 let (metadata, witness_table) = build_type();
249 debug_assert_eq!(
250 field_offset(metadata, 1),
251 ID_OFFSET,
252 "the id moved; the body witness reads it at a fixed offset"
253 );
254
255 let mut value = vec![0u8; instance_bytes(metadata)];
262 value[..8].copy_from_slice(&initial.to_le_bytes());
263 value[ID_OFFSET..ID_OFFSET + 8].copy_from_slice(&id.to_le_bytes());
264
265 Self { metadata, witness_table, value, id }
266 }
267 }
268
269 pub fn set(&self, value: i64) -> bool {
271 set_state(self.id, value)
272 }
273
274 pub fn set_animated(&self, value: i64) {
276 set_state_animated(self.id, value);
277 }
278
279 pub fn set_animated_with(&self, value: i64, animation: u64) {
282 set_state_animated_with(self.id, value, animation);
283 }
284
285 pub fn as_view(&self) -> ViewHandle {
287 unsafe { copy_as_view(&self.value, self.metadata, self.witness_table) }
288 }
289}
290
291const ID_OFFSET: usize = 16;
302
303
304struct FieldSpec {
309 mangled_type: &'static [u8],
314 name: &'static [u8],
315 meta: *const c_void,
324}
325
326struct TypeLayout {
329 fields: Vec<(usize, usize)>,
333 size: usize,
334}
335
336static LAYOUTS: std::sync::Mutex<Option<std::collections::HashMap<usize, TypeLayout>>> =
340 std::sync::Mutex::new(None);
341
342fn with_layouts<R>(f: impl FnOnce(&mut std::collections::HashMap<usize, TypeLayout>) -> R) -> R {
343 let mut g = LAYOUTS.lock().expect("layout registry poisoned");
344 f(g.get_or_insert_with(std::collections::HashMap::new))
345}
346
347unsafe fn field_vwt(
348 meta: *const c_void,
349) -> *const swift_runtime_sys::SwiftABI::ValueWitnessTable {
350 unsafe { swift_runtime_sys::SwiftABI::get_value_witness_table(meta) }
351}
352
353unsafe fn for_each_field(
358 meta: *const c_void,
359 mut op: impl FnMut(*const c_void, usize),
360) -> bool {
361 let fields = with_layouts(|m| m.get(&(meta as usize)).map(|l| l.fields.clone()));
362 match fields {
363 Some(fields) => {
364 for (fm, off) in fields {
365 op(fm as *const c_void, off);
366 }
367 true
368 }
369 None => false,
370 }
371}
372
373unsafe fn instance_bytes(meta: *const c_void) -> usize {
375 let n = with_layouts(|m| m.get(&(meta as usize)).map_or(0, |l| l.size));
376 assert!(n > 0, "no layout registered for this synthesised type");
377 n
378}
379
380unsafe extern "C" fn fw_destroy(value: *mut u8, meta: *const c_void) {
387 unsafe {
388 for_each_field(meta, |fm, off| {
389 ((*field_vwt(fm)).destroy)(value.add(off) as *mut c_void, fm);
390 });
391 }
392}
393
394unsafe extern "C" fn fw_init_with_copy(
395 dest: *mut u8,
396 src: *mut u8,
397 meta: *const c_void,
398) -> *mut u8 {
399 unsafe {
400 for_each_field(meta, |fm, off| {
401 ((*field_vwt(fm)).initialize_with_copy)(
402 dest.add(off) as *mut c_void,
403 src.add(off) as *mut c_void,
404 fm,
405 );
406 });
407 }
408 dest
409}
410
411unsafe extern "C" fn fw_assign_with_copy(
412 dest: *mut u8,
413 src: *mut u8,
414 meta: *const c_void,
415) -> *mut u8 {
416 unsafe {
417 for_each_field(meta, |fm, off| {
418 ((*field_vwt(fm)).assign_with_copy)(
419 dest.add(off) as *mut c_void,
420 src.add(off) as *mut c_void,
421 fm,
422 );
423 });
424 }
425 dest
426}
427
428unsafe extern "C" fn fw_init_with_take(
429 dest: *mut u8,
430 src: *mut u8,
431 meta: *const c_void,
432) -> *mut u8 {
433 unsafe {
434 for_each_field(meta, |fm, off| {
435 ((*field_vwt(fm)).initialize_with_take)(
436 dest.add(off) as *mut c_void,
437 src.add(off) as *mut c_void,
438 fm,
439 );
440 });
441 }
442 dest
443}
444
445unsafe extern "C" fn fw_assign_with_take(
446 dest: *mut u8,
447 src: *mut u8,
448 meta: *const c_void,
449) -> *mut u8 {
450 unsafe {
451 for_each_field(meta, |fm, off| {
452 ((*field_vwt(fm)).assign_with_take)(
453 dest.add(off) as *mut c_void,
454 src.add(off) as *mut c_void,
455 fm,
456 );
457 });
458 }
459 dest
460}
461
462unsafe extern "C" fn fw_init_buffer(dest: *mut u8, src: *mut u8, meta: *const c_void) -> *mut u8 {
465 unsafe { fw_init_with_copy(dest, src, meta) }
466}
467
468unsafe extern "C" fn fw_get_tag(_v: *const u8, _n: u32, _m: *const c_void) -> u32 {
470 0
471}
472
473unsafe extern "C" fn fw_store_tag(_v: *mut u8, _w: u32, _n: u32, _m: *const c_void) {}
474
475fn delegating_vwt(size: usize, align: usize) -> *const c_void {
478 unsafe {
479 let vwt = libc::malloc(96) as *mut u8;
480 assert!(!vwt.is_null());
481 core::ptr::write_bytes(vwt, 0, 96);
482 let f = vwt as *mut *const c_void;
483 *f.add(0) = fw_init_buffer as *const c_void;
484 *f.add(1) = fw_destroy as *const c_void;
485 *f.add(2) = fw_init_with_copy as *const c_void;
486 *f.add(3) = fw_assign_with_copy as *const c_void;
487 *f.add(4) = fw_init_with_take as *const c_void;
488 *f.add(5) = fw_assign_with_take as *const c_void;
489 *f.add(6) = fw_get_tag as *const c_void;
490 *f.add(7) = fw_store_tag as *const c_void;
491 *(vwt.add(64) as *mut usize) = size;
492 *(vwt.add(72) as *mut usize) = size;
493 *(vwt.add(80) as *mut u32) = 0x0001_0000 | (align as u32 - 1);
496 *(vwt.add(84) as *mut u32) = 0; vwt as *const c_void
498 }
499}
500
501unsafe fn copy_as_view(
517 value: &[u8],
518 metadata: *const c_void,
519 witness_table: *const c_void,
520) -> ViewHandle {
521 unsafe {
522 let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(metadata);
523 let mut owned = vec![0u8; abi::type_bytes(metadata)];
524 (vwt.initialize_with_copy)(
525 owned.as_mut_ptr() as *mut c_void,
526 value.as_ptr() as *mut c_void,
527 metadata,
528 );
529 ViewHandle::wrap(owned.as_ptr() as *const c_void, metadata, witness_table)
530 }
531}
532
533unsafe fn destroy_instance(value: &mut [u8], metadata: *const c_void) {
535 unsafe {
536 let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(metadata);
537 if vwt.size > 0 {
538 (vwt.destroy)(value.as_mut_ptr() as *mut c_void, metadata);
539 }
540 }
541}
542
543unsafe fn field_offset(metadata: *const c_void, i: usize) -> usize {
549 unsafe { *((metadata as *const u8).add(16 + 4 * i) as *const u32) as usize }
550}
551
552unsafe fn emit_type(
567 type_name: &[u8],
568 self_mangled: &[u8],
569 fields: &[FieldSpec],
570 body: *const c_void,
571) -> (*const c_void, *const c_void) {
572 const MODULE_NAME: &[u8] = b"rswift\0";
573 const MODULE: usize = 0;
574 const MODULE_NAME_OFF: usize = 16;
575 const STRUCT: usize = 32;
576 const TYPE_NAME_OFF: usize = 64;
577 const FIELD_DESC: usize = 128;
584
585 let n = fields.len();
586 assert!(n > 0, "a synthesised struct needs at least one field");
587
588 let mut offsets = Vec::with_capacity(n);
593 let mut at = 0usize;
594 let mut align = 1usize;
595 for f in fields {
596 let vw = unsafe { &*field_vwt(f.meta) };
597 let a = vw.flags.alignment().max(1);
598 align = align.max(a);
599 at = (at + a - 1) & !(a - 1);
600 offsets.push(at);
601 at += vw.stride.max(vw.size).max(1);
602 }
603 let size = ((at + align - 1) & !(align - 1)).max(1);
604 let vwt = delegating_vwt(size, align);
605 assert!(MODULE_NAME_OFF + MODULE_NAME.len() <= STRUCT);
606 assert!(
607 TYPE_NAME_OFF + type_name.len() <= FIELD_DESC,
608 "the synthesised type name {:?} needs {} bytes and there are {}",
609 core::str::from_utf8(type_name).unwrap_or("<not utf-8>"),
610 type_name.len(),
611 FIELD_DESC - TYPE_NAME_OFF
612 );
613
614 let field_desc_end = FIELD_DESC + 16 + 12 * n;
616 let mut strings: Vec<(usize, &[u8])> = Vec::with_capacity(2 * n + 3);
617 strings.push((MODULE_NAME_OFF, MODULE_NAME));
618 strings.push((TYPE_NAME_OFF, type_name));
619 let mut at = field_desc_end;
620 let mut field_string_offsets = Vec::with_capacity(n);
621 for f in fields {
622 let t = at;
623 strings.push((at, f.mangled_type));
624 at += f.mangled_type.len();
625 let name = at;
626 strings.push((at, f.name));
627 at += f.name.len();
628 field_string_offsets.push((t, name));
629 }
630 let self_mangled_off = at;
631 strings.push((at, self_mangled));
632 at += self_mangled.len();
633
634 let align8 = |x: usize| (x + 7) & !7;
635 let proto_slot = align8(at);
636 let conf = proto_slot + 16;
637 let record = conf + 24;
638 let witness = record + 8;
639 let total = witness + 7 * 8 + 8;
640
641 let block = unsafe { libc::malloc(total) } as *mut u8;
642 assert!(!block.is_null());
643 unsafe {
644 core::ptr::write_bytes(block, 0, total);
645 for (off, bytes) in strings {
646 core::ptr::copy_nonoverlapping(bytes.as_ptr(), block.add(off), bytes.len());
647 }
648 }
649
650 unsafe fn rel(field: *const u8, target: *const u8) -> i32 {
651 i32::try_from(target as isize - field as isize).expect("relative pointer out of range")
652 }
653
654 unsafe {
655 let m = block.add(MODULE);
657 *(m as *mut u32) = 0x40; *(m.add(4) as *mut i32) = 0;
659 *(m.add(8) as *mut i32) = rel(m.add(8), block.add(MODULE_NAME_OFF));
660
661 let d = block.add(STRUCT);
663 *(d as *mut u32) = 0x51; *(d.add(4) as *mut i32) = rel(d.add(4), m);
665 *(d.add(8) as *mut i32) = rel(d.add(8), block.add(TYPE_NAME_OFF));
666 *(d.add(12) as *mut i32) = 0; *(d.add(16) as *mut i32) = rel(d.add(16), block.add(FIELD_DESC));
668 *(d.add(20) as *mut u32) = n as u32; *(d.add(24) as *mut u32) = 2; let f = block.add(FIELD_DESC);
674 *(f as *mut i32) = rel(f, block.add(self_mangled_off));
675 *(f.add(4) as *mut i32) = 0; *(f.add(8) as *mut u16) = 0; *(f.add(10) as *mut u16) = 12; *(f.add(12) as *mut u32) = n as u32;
679 for (i, (type_off, name_off)) in field_string_offsets.iter().enumerate() {
680 let r = f.add(16 + 12 * i);
681 *(r as *mut u32) = 0x2; *(r.add(4) as *mut i32) = rel(r.add(4), block.add(*type_off));
683 *(r.add(8) as *mut i32) = rel(r.add(8), block.add(*name_off));
684 }
685
686 let meta_bytes = 24 + 4 * n;
688 let meta = libc::malloc(meta_bytes) as *mut *const c_void;
689 assert!(!meta.is_null());
690 core::ptr::write_bytes(meta as *mut u8, 0, meta_bytes);
691 *meta.add(0) = vwt;
692 *(meta.add(1) as *mut usize) = 0x200; *meta.add(2) = d as *const c_void;
694 for (i, off) in offsets.iter().enumerate() {
695 *((meta as *mut u8).add(24 + 4 * i) as *mut u32) = *off as u32;
696 }
697 let metadata = (meta as *const u8).add(8) as *const c_void;
698
699 with_layouts(|m| {
702 m.insert(
703 metadata as usize,
704 TypeLayout {
705 fields: fields
706 .iter()
707 .zip(&offsets)
708 .map(|(f, off)| (f.meta as usize, *off))
709 .collect(),
710 size,
711 },
712 )
713 });
714
715 let wt = block.add(witness) as *mut *const c_void;
724 *wt.add(0) = block.add(conf) as *const c_void;
725 *wt.add(1) = resolve::anyview_wt();
726 *wt.add(2) = resolve::anyview_meta();
727 *wt.add(3) = resolve::view_make_view_default();
728 *wt.add(4) = resolve::view_make_view_list_default();
729 *wt.add(5) = resolve::view_list_count_default();
730 *wt.add(6) = body;
731
732 *(block.add(proto_slot) as *mut *const c_void) = resolve::view_proto();
735 let c = block.add(conf);
736 *(c as *mut i32) = rel(c, block.add(proto_slot)) | 1; *(c.add(4) as *mut i32) = rel(c.add(4), d);
738 *(c.add(8) as *mut i32) = rel(c.add(8), block.add(witness));
739 *(c.add(12) as *mut u32) = 0;
740
741 let rec = block.add(record);
742 *(rec as *mut i32) = rel(rec, c);
743 type Register = unsafe extern "C" fn(*const u8, *const u8);
744 let reg = libc::dlsym(
745 (-2isize) as *mut c_void,
746 c"swift_registerProtocolConformances".as_ptr(),
747 );
748 assert!(!reg.is_null(), "swift_registerProtocolConformances not found");
749 let reg: Register = core::mem::transmute(reg);
750 reg(rec, rec.add(4));
751
752 (metadata, wt as *const c_void)
753 }
754}
755
756pub(crate) unsafe fn emit_int_carrier(
771 type_name: &'static [u8],
772 self_mangled: &'static [u8],
773) -> (*const c_void, *const c_void) {
774 unsafe {
775 let (metadata, _) = emit_type(
776 type_name,
777 self_mangled,
778 &[FieldSpec { mangled_type: b"Si\0", name: b"index\0", meta: resolve::int_meta() }],
779 stub_body as *const c_void,
780 );
781 let descriptor = *(metadata as *const *const c_void).add(1);
782 (descriptor, metadata)
783 }
784}
785
786unsafe extern "C" fn stub_body(out: *mut u8, _payload: *mut c_void) {
788 unsafe { *(out as *mut u64) = 0 };
789}
790
791unsafe fn build_type() -> (*const c_void, *const c_void) {
793 unsafe {
794 emit_type(
795 b"RustView\0",
796 b"6rswift8RustViewV\0",
797 &[
798 FieldSpec {
799 mangled_type: b"7SwiftUI5StateVySiG\0",
800 name: b"_value\0",
801 meta: abi::generic_metadata1(resolve::state_ma(), resolve::int_meta()),
802 },
803 FieldSpec { mangled_type: b"Si\0", name: b"id\0", meta: resolve::int_meta() },
804 ],
805 view_body_thunk as *const c_void,
806 )
807 }
808}
809
810static PENDING_WRITE: std::sync::Mutex<(i64, i64)> = std::sync::Mutex::new((0, 0));
821
822unsafe extern "C" fn animated_write(_out: *mut u8, _payload: *mut c_void) {
824 let (id, value) = *PENDING_WRITE.lock().expect("pending write poisoned");
825 set_state(id, value);
826}
827
828mod root {
846 use super::{set_state_animated_with, StatefulView};
847 use crate::views::ViewHandle;
848 use std::sync::atomic::{AtomicI64, Ordering};
849
850 pub(super) static ID: AtomicI64 = AtomicI64::new(-1);
851 static GENERATION: AtomicI64 = AtomicI64::new(1);
852
853 thread_local! {
854 static VIEW: std::cell::OnceCell<StatefulView> = const { std::cell::OnceCell::new() };
855 }
856
857 pub(super) fn view(builder: fn(i64) -> ViewHandle) -> ViewHandle {
858 VIEW.with(|cell| {
859 let sv = cell.get_or_init(|| {
860 let sv = StatefulView::new(GENERATION.load(Ordering::Relaxed), builder);
861 ID.store(sv.id, Ordering::Release);
862 sv
863 });
864 sv.as_view()
865 })
866 }
867
868 pub(super) fn bump(animation: Option<u64>) {
869 let id = ID.load(Ordering::Acquire);
870 if id < 0 {
871 return;
872 }
873 let n = GENERATION.fetch_add(1, Ordering::Relaxed) + 1;
874 match animation {
875 Some(a) => set_state_animated_with(id, n, a),
876 None => {
877 super::set_state(id, n);
878 }
879 }
880 }
881}
882
883pub fn root_view(builder: fn(i64) -> ViewHandle) -> ViewHandle {
891 root::view(builder)
892}
893
894pub fn refresh() {
899 root::bump(None);
900}
901
902pub fn refresh_animated(animation: u64) {
904 root::bump(Some(animation));
905}
906
907pub fn ease_in_out(duration: f64) -> u64 {
912 unsafe {
913 let meta = abi::metadata0(resolve::animation_ma());
914 let out: u64;
915 core::arch::asm!("blr {f}", f = in(reg) resolve::animation_ease_in_out(),
916 in("d0") duration,
917 in("x20") meta,
918 lateout("x0") out,
919 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
920 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x8") _,
921 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
922 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
923 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
924 );
925 out
926 }
927}
928
929pub fn set_state_animated_with(id: i64, value: i64, animation: u64) {
931 set_animated_inner(id, value, Some(animation))
932}
933
934pub fn set_state_animated(id: i64, value: i64) {
935 set_animated_inner(id, value, None)
936}
937
938fn set_animated_inner(id: i64, value: i64, animation: Option<u64>) {
939 *PENDING_WRITE.lock().expect("pending write poisoned") = (id, value);
940 unsafe {
941 let anim_meta = abi::metadata0(resolve::animation_ma());
944 let anim = if let Some(a) = animation { a } else {
945 let out: u64;
946 core::arch::asm!("blr {f}", f = in(reg) resolve::animation_default(),
947 in("x20") anim_meta,
948 lateout("x0") out,
949 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
950 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x8") _,
951 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
952 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
953 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
954 );
955 out
956 };
957
958 let ctx = Box::leak(Box::new(abi::ClosureCtx::new(
959 animated_write,
960 core::ptr::null_mut(),
961 ))) as *mut abi::ClosureCtx;
962
963 let mut out = [0u8; 8];
967 core::arch::asm!("blr {f}", f = in(reg) resolve::with_animation(),
968 in("x0") anim,
969 in("x1") abi::swift_closure_thunk as *const c_void,
970 in("x2") ctx,
971 in("x3") resolve::sym(c"$sytN"),
972 in("x8") out.as_mut_ptr(),
973 inout("x21") 0u64 => _,
974 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
975 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
976 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
977 lateout("x17") _, lateout("lr") _, lateout("x20") _,
978 clobber_abi("C"),
979 );
980 }
981}
982
983const STORED_ID_OFFSET: usize = 8;
1028
1029pub trait StoredValue: Clone + Send + 'static {
1046 fn metadata() -> *const c_void;
1048 fn field_type() -> &'static [u8];
1050 fn mangled() -> &'static str;
1052 fn buffer_bytes() -> usize;
1054 unsafe fn init_storage(&self, key: &str) -> u64;
1059 unsafe fn decode(buf: &[u8]) -> Self;
1066 fn encode(&self) -> Vec<u8>;
1068}
1069
1070impl StoredValue for bool {
1071 fn metadata() -> *const c_void {
1072 resolve::bool_meta()
1073 }
1074 fn field_type() -> &'static [u8] {
1075 b"7SwiftUI10AppStorageVySbG\0"
1076 }
1077 fn mangled() -> &'static str {
1078 mangle::BOOL
1079 }
1080 fn buffer_bytes() -> usize {
1081 1
1082 }
1083 unsafe fn init_storage(&self, key: &str) -> u64 {
1084 unsafe { app_storage_init_word(resolve::app_storage_bool_init(), u64::from(*self), key) }
1085 }
1086 unsafe fn decode(buf: &[u8]) -> Self {
1087 buf[0] != 0
1088 }
1089 fn encode(&self) -> Vec<u8> {
1090 vec![u8::from(*self)]
1091 }
1092}
1093
1094impl StoredValue for i64 {
1095 fn metadata() -> *const c_void {
1096 resolve::int_meta()
1097 }
1098 fn field_type() -> &'static [u8] {
1099 b"7SwiftUI10AppStorageVySiG\0"
1100 }
1101 fn mangled() -> &'static str {
1102 mangle::INT
1103 }
1104 fn buffer_bytes() -> usize {
1105 8
1106 }
1107 unsafe fn init_storage(&self, key: &str) -> u64 {
1108 unsafe { app_storage_init_word(resolve::app_storage_int_init(), *self as u64, key) }
1109 }
1110 unsafe fn decode(buf: &[u8]) -> Self {
1111 i64::from_le_bytes(buf[..8].try_into().expect("Int"))
1112 }
1113 fn encode(&self) -> Vec<u8> {
1114 self.to_le_bytes().to_vec()
1115 }
1116}
1117
1118impl StoredValue for f64 {
1119 fn metadata() -> *const c_void {
1120 resolve::double_meta()
1121 }
1122 fn field_type() -> &'static [u8] {
1123 b"7SwiftUI10AppStorageVySdG\0"
1124 }
1125 fn mangled() -> &'static str {
1126 mangle::DOUBLE
1127 }
1128 fn buffer_bytes() -> usize {
1129 8
1130 }
1131 unsafe fn init_storage(&self, key: &str) -> u64 {
1132 unsafe {
1133 let k = abi::swift_string(key);
1135 let out: u64;
1136 core::arch::asm!("blr {f}", f = in(reg) resolve::app_storage_double_init(),
1137 in("d0") *self,
1138 inlateout("x0") u64::from_le_bytes(k[..8].try_into().expect("key lo")) => out,
1139 in("x1") u64::from_le_bytes(k[8..].try_into().expect("key hi")),
1140 in("x2") 0u64, lateout("x3") _, lateout("x4") _, lateout("x5") _, lateout("x6") _,
1142 lateout("x7") _, lateout("x8") _, lateout("x9") _, lateout("x10") _,
1143 lateout("x11") _, lateout("x12") _, lateout("x13") _, lateout("x14") _,
1144 lateout("x15") _, lateout("x16") _, lateout("x17") _, lateout("lr") _,
1145 lateout("x20") _, lateout("x21") _, clobber_abi("C"),
1146 );
1147 assert!(out != 0, "AppStorage<Double>.init returned nothing");
1148 out
1149 }
1150 }
1151 unsafe fn decode(buf: &[u8]) -> Self {
1152 f64::from_le_bytes(buf[..8].try_into().expect("Double"))
1153 }
1154 fn encode(&self) -> Vec<u8> {
1155 self.to_le_bytes().to_vec()
1156 }
1157}
1158
1159impl StoredValue for String {
1160 fn metadata() -> *const c_void {
1161 resolve::string_meta()
1162 }
1163 fn field_type() -> &'static [u8] {
1164 b"7SwiftUI10AppStorageVySSG\0"
1165 }
1166 fn mangled() -> &'static str {
1167 mangle::STRING
1168 }
1169 fn buffer_bytes() -> usize {
1170 16
1171 }
1172 unsafe fn init_storage(&self, key: &str) -> u64 {
1173 unsafe {
1174 let v = abi::swift_string(self);
1175 let k = abi::swift_string(key);
1176 let out: u64;
1177 core::arch::asm!("blr {f}", f = in(reg) resolve::app_storage_string_init(),
1178 inlateout("x0") u64::from_le_bytes(v[..8].try_into().expect("v lo")) => out,
1179 in("x1") u64::from_le_bytes(v[8..].try_into().expect("v hi")),
1180 in("x2") u64::from_le_bytes(k[..8].try_into().expect("k lo")),
1181 in("x3") u64::from_le_bytes(k[8..].try_into().expect("k hi")),
1182 in("x4") 0u64, lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x8") _,
1184 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
1185 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
1186 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
1187 clobber_abi("C"),
1188 );
1189 assert!(out != 0, "AppStorage<String>.init returned nothing");
1190 out
1191 }
1192 }
1193 unsafe fn decode(buf: &[u8]) -> Self {
1194 unsafe {
1195 let bytes: [u8; 16] = buf[..16].try_into().expect("String");
1196 let s = abi::read_swift_string(bytes);
1197 swift_runtime_sys::BridgeObject::swift_bridgeObjectRelease(
1201 u64::from_le_bytes(bytes[8..].try_into().expect("bridge word")) as *mut c_void,
1202 );
1203 s
1204 }
1205 }
1206 fn encode(&self) -> Vec<u8> {
1207 unsafe { abi::swift_string(self).to_vec() }
1208 }
1209}
1210
1211unsafe fn app_storage_init_word(func: *const c_void, value: u64, key: &str) -> u64 {
1214 unsafe {
1215 let k = abi::swift_string(key);
1216 let out: u64;
1217 core::arch::asm!("blr {f}", f = in(reg) func,
1218 inlateout("x0") value => out,
1219 in("x1") u64::from_le_bytes(k[..8].try_into().expect("key lo")),
1220 in("x2") u64::from_le_bytes(k[8..].try_into().expect("key hi")),
1221 in("x3") 0u64, lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
1223 lateout("x8") _, lateout("x9") _, lateout("x10") _, lateout("x11") _,
1224 lateout("x12") _, lateout("x13") _, lateout("x14") _, lateout("x15") _,
1225 lateout("x16") _, lateout("x17") _, lateout("lr") _, lateout("x20") _,
1226 lateout("x21") _, clobber_abi("C"),
1227 );
1228 assert!(out != 0, "AppStorage.init returned nothing");
1229 out
1230 }
1231}
1232
1233unsafe fn app_storage_get<T: StoredValue>(location: u64) -> T {
1249 unsafe {
1250 let mut buf = vec![0u8; T::buffer_bytes()];
1251 swift_runtime_sys::RuntimeRaw::swift_retain(location as *mut c_void);
1253 core::arch::asm!("blr {f}", f = in(reg) resolve::app_storage_wrapped_get(),
1254 in("x8") buf.as_mut_ptr(),
1255 in("x0") location,
1256 in("x1") T::metadata(),
1257 lateout("x2") _, lateout("x3") _, lateout("x4") _, lateout("x5") _,
1258 lateout("x6") _, lateout("x7") _, lateout("x9") _, lateout("x10") _,
1259 lateout("x11") _, lateout("x12") _, lateout("x13") _, lateout("x14") _,
1260 lateout("x15") _, lateout("x16") _, lateout("x17") _, lateout("lr") _,
1261 lateout("x20") _, lateout("x21") _, clobber_abi("C"),
1262 );
1263 swift_runtime_sys::RuntimeRaw::swift_release(location as *mut c_void);
1264 T::decode(&buf)
1265 }
1266}
1267
1268unsafe fn app_storage_set<T: StoredValue>(location: u64, value: &T) {
1270 unsafe {
1271 let mut v = value.encode();
1272 swift_runtime_sys::RuntimeRaw::swift_retain(location as *mut c_void);
1273 core::arch::asm!("blr {f}", f = in(reg) resolve::app_storage_wrapped_set(),
1274 in("x0") v.as_mut_ptr(),
1275 in("x1") location,
1276 in("x2") T::metadata(),
1277 lateout("x3") _, lateout("x4") _, lateout("x5") _, lateout("x6") _,
1278 lateout("x7") _, lateout("x8") _, lateout("x9") _, lateout("x10") _,
1279 lateout("x11") _, lateout("x12") _, lateout("x13") _, lateout("x14") _,
1280 lateout("x15") _, lateout("x16") _, lateout("x17") _, lateout("lr") _,
1281 lateout("x20") _, lateout("x21") _, clobber_abi("C"),
1282 );
1283 swift_runtime_sys::RuntimeRaw::swift_release(location as *mut c_void);
1284 }
1285}
1286
1287unsafe fn app_storage_projected<T: StoredValue>(location: u64) -> Vec<u8> {
1290 unsafe {
1291 let meta = abi::resolve_type_by_mangled_name(
1292 mangle::bound("7SwiftUI7BindingV", &[T::mangled()]).as_bytes(),
1293 );
1294 assert!(!meta.is_null(), "Binding metadata");
1295 let mut out = vec![0u8; abi::type_bytes(meta)];
1296 swift_runtime_sys::RuntimeRaw::swift_retain(location as *mut c_void);
1297 core::arch::asm!("blr {f}", f = in(reg) resolve::app_storage_projected_get(),
1298 in("x8") out.as_mut_ptr(),
1299 in("x0") location,
1300 in("x1") T::metadata(),
1301 lateout("x2") _, lateout("x3") _, lateout("x4") _, lateout("x5") _,
1302 lateout("x6") _, lateout("x7") _, lateout("x9") _, lateout("x10") _,
1303 lateout("x11") _, lateout("x12") _, lateout("x13") _, lateout("x14") _,
1304 lateout("x15") _, lateout("x16") _, lateout("x17") _, lateout("lr") _,
1305 lateout("x20") _, lateout("x21") _, clobber_abi("C"),
1306 );
1307 swift_runtime_sys::RuntimeRaw::swift_release(location as *mut c_void);
1308 out
1309 }
1310}
1311
1312struct StoredInstance {
1315 render: Box<dyn Fn(u64) -> ViewHandle + Send>,
1318 runs: usize,
1319}
1320
1321static STORED: std::sync::Mutex<Option<std::collections::HashMap<i64, StoredInstance>>> =
1322 std::sync::Mutex::new(None);
1323
1324fn with_stored<R>(f: impl FnOnce(&mut std::collections::HashMap<i64, StoredInstance>) -> R) -> R {
1325 let mut g = STORED.lock().expect("stored registry poisoned");
1326 f(g.get_or_insert_with(std::collections::HashMap::new))
1327}
1328
1329core::arch::global_asm!(
1330 ".p2align 2",
1331 ".globl _rswift_stored_body_thunk",
1332 "_rswift_stored_body_thunk:",
1333 "mov x1, x20",
1334 "mov x0, x8",
1335 "b _rswift_stored_body_getter",
1336);
1337
1338unsafe extern "C" {
1339 #[link_name = "rswift_stored_body_thunk"]
1340 fn stored_body_thunk();
1341}
1342
1343#[unsafe(no_mangle)]
1344unsafe extern "C" fn rswift_stored_body_getter(out: *mut u8, this: *const u8) {
1345 unsafe {
1346 let id = *(this.add(STORED_ID_OFFSET) as *const i64);
1347 let location = *(this as *const u64);
1348 let view = with_stored(|m| {
1349 let inst = m.get_mut(&id)?;
1350 inst.runs += 1;
1351 Some((inst.render)(location))
1352 });
1353 *(out as *mut u64) = view.unwrap_or_else(crate::views::empty_view).into_anyview_word();
1354 }
1355}
1356
1357
1358pub struct StoredView<T: StoredValue> {
1380 pub metadata: *const c_void,
1381 pub witness_table: *const c_void,
1382 value: Vec<u8>,
1383 pub id: i64,
1384 key: String,
1385 marker: core::marker::PhantomData<fn() -> T>,
1386}
1387
1388impl<T: StoredValue> StoredView<T> {
1389 pub fn new(key: &str, default: T, builder: impl Fn(T) -> ViewHandle + Send + 'static) -> Self {
1391 unsafe {
1392 let id = NEXT_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
1393 with_stored(|m| {
1394 m.insert(
1395 id,
1396 StoredInstance {
1397 render: Box::new(move |loc| builder(app_storage_get::<T>(loc))),
1398 runs: 0,
1399 },
1400 )
1401 });
1402 let (metadata, witness_table) = emit_type(
1403 b"RustStored\0",
1404 b"6rswift10RustStoredV\0",
1405 &[
1406 FieldSpec {
1407 mangled_type: T::field_type(),
1408 name: b"_flag\0",
1409 meta: abi::resolve_type_by_mangled_name(
1410 &T::field_type()[..T::field_type().len() - 1],
1411 ),
1412 },
1413 FieldSpec { mangled_type: b"Si\0", name: b"id\0", meta: resolve::int_meta() },
1414 ],
1415 stored_body_thunk as *const c_void,
1416 );
1417 debug_assert_eq!(
1418 field_offset(metadata, 1),
1419 STORED_ID_OFFSET,
1420 "the id moved; the body witness reads it at a fixed offset"
1421 );
1422 let mut value = vec![0u8; instance_bytes(metadata)];
1426 value[..8].copy_from_slice(&default.init_storage(key).to_le_bytes());
1427 value[STORED_ID_OFFSET..STORED_ID_OFFSET + 8].copy_from_slice(&id.to_le_bytes());
1428 Self {
1429 metadata,
1430 witness_table,
1431 value,
1432 id,
1433 key: key.to_owned(),
1434 marker: core::marker::PhantomData,
1435 }
1436 }
1437 }
1438
1439 fn location(&self) -> u64 {
1440 u64::from_le_bytes(self.value[..8].try_into().expect("location"))
1441 }
1442
1443 pub fn key(&self) -> &str {
1445 &self.key
1446 }
1447
1448 pub fn get(&self) -> T {
1450 unsafe { app_storage_get::<T>(self.location()) }
1451 }
1452
1453 pub fn set(&self, value: T) {
1455 unsafe { app_storage_set::<T>(self.location(), &value) }
1456 }
1457
1458 pub fn runs(&self) -> usize {
1460 with_stored(|m| m.get(&self.id).map_or(0, |i| i.runs))
1461 }
1462
1463 pub fn binding(&self) -> Vec<u8> {
1470 unsafe { app_storage_projected::<T>(self.location()) }
1471 }
1472
1473 pub fn as_view(&self) -> ViewHandle {
1475 unsafe { copy_as_view(&self.value, self.metadata, self.witness_table) }
1476 }
1477}
1478
1479pub trait EnvKey: Copy + 'static {
1499 type Value: Clone + Send + 'static;
1501 fn field_type() -> &'static [u8];
1503 fn value_type() -> &'static [u8];
1509 fn key_path() -> u64;
1511 fn buffer_bytes() -> usize;
1513 unsafe fn decode(buf: &[u8]) -> Self::Value;
1518 fn encode(value: &Self::Value) -> u8;
1525}
1526
1527macro_rules! env_key {
1535 ($(
1536 $(#[$meta:meta])*
1537 $name:ident {
1538 value: $value:ty,
1539 field: $field:expr,
1540 value_type: $value_type:expr,
1541 symbols: ($getter:ident, $setter:ident, $descriptor:ident),
1542 bytes: $bytes:expr,
1543 decode: |$buf:ident| $decode:expr,
1544 encode: |$enc:ident| $encode:expr,
1545 }
1546 )*) => {$(
1547 $(#[$meta])*
1548 #[derive(Clone, Copy)]
1549 pub struct $name;
1550
1551 impl EnvKey for $name {
1552 type Value = $value;
1553 fn field_type() -> &'static [u8] {
1554 $field
1555 }
1556 fn value_type() -> &'static [u8] {
1557 $value_type
1558 }
1559 fn key_path() -> u64 {
1560 use std::sync::atomic::{AtomicU64, Ordering};
1561 static CACHE: AtomicU64 = AtomicU64::new(0);
1562 static mut SLOT: crate::keypath::Slot = crate::keypath::Slot::new();
1563 let hit = CACHE.load(Ordering::Relaxed);
1564 if hit != 0 {
1565 return hit;
1566 }
1567 unsafe {
1568 let kp = crate::keypath::build(
1569 &mut *(&raw mut SLOT),
1570 crate::keypath::Property {
1571 getter: resolve::$getter(),
1572 setter: resolve::$setter(),
1573 descriptor: resolve::$descriptor(),
1574 root: b"7SwiftUI17EnvironmentValuesV",
1575 value: $value_type,
1576 },
1577 crate::keypath::next_thunks(),
1578 );
1579 CACHE.store(kp, Ordering::Relaxed);
1580 kp
1581 }
1582 }
1583 fn buffer_bytes() -> usize {
1584 $bytes
1585 }
1586 unsafe fn decode($buf: &[u8]) -> Self::Value {
1587 $decode
1588 }
1589 fn encode($enc: &Self::Value) -> u8 {
1590 $encode
1591 }
1592 }
1593 )*};
1594}
1595
1596env_key! {
1597 ColorSchemeKey {
1599 value: crate::views::ColorScheme,
1600 field: b"7SwiftUI11EnvironmentVyAA11ColorSchemeOG\0",
1601 value_type: b"7SwiftUI11ColorSchemeO",
1602 symbols: (env_color_scheme_getter, env_color_scheme_setter, env_color_scheme_descriptor),
1603 bytes: 1,
1604 decode: |b| match b[0] {
1605 0 => crate::views::ColorScheme::Light,
1606 _ => crate::views::ColorScheme::Dark,
1607 },
1608 encode: |v| match v {
1609 crate::views::ColorScheme::Light => 0,
1610 crate::views::ColorScheme::Dark => 1,
1611 },
1612 }
1613
1614 IsEnabledKey {
1616 value: bool,
1617 field: b"7SwiftUI11EnvironmentVySbG\0",
1618 value_type: b"Sb",
1619 symbols: (env_is_enabled_getter, env_is_enabled_setter, env_is_enabled_descriptor),
1620 bytes: 1,
1621 decode: |b| b[0] != 0,
1622 encode: |v| u8::from(*v),
1623 }
1624
1625 LayoutDirectionKey {
1627 value: crate::views::LayoutDirection,
1628 field: b"7SwiftUI11EnvironmentVyAA15LayoutDirectionOG\0",
1629 value_type: b"7SwiftUI15LayoutDirectionO",
1630 symbols: (
1631 env_layout_direction_getter,
1632 env_layout_direction_setter,
1633 env_layout_direction_descriptor
1634 ),
1635 bytes: 1,
1636 decode: |b| match b[0] {
1637 0 => crate::views::LayoutDirection::LeftToRight,
1638 _ => crate::views::LayoutDirection::RightToLeft,
1639 },
1640 encode: |v| match v {
1641 crate::views::LayoutDirection::LeftToRight => 0,
1642 crate::views::LayoutDirection::RightToLeft => 1,
1643 },
1644 }
1645
1646 DynamicTypeSizeKey {
1648 value: crate::views::DynamicTypeSize,
1649 field: b"7SwiftUI11EnvironmentVyAA15DynamicTypeSizeOG\0",
1650 value_type: b"7SwiftUI15DynamicTypeSizeO",
1651 symbols: (
1652 env_dynamic_type_size_getter,
1653 env_dynamic_type_size_setter,
1654 env_dynamic_type_size_descriptor
1655 ),
1656 bytes: 1,
1657 decode: |b| {
1658 use crate::views::DynamicTypeSize::*;
1659 [
1660 XSmall, Small, Medium, Large, XLarge, XxLarge, XxxLarge,
1661 Accessibility1, Accessibility2, Accessibility3, Accessibility4,
1662 Accessibility5,
1663 ][(b[0] as usize).min(11)]
1664 },
1665 encode: |v| {
1666 use crate::views::DynamicTypeSize::*;
1667 [
1668 XSmall, Small, Medium, Large, XLarge, XxLarge, XxxLarge,
1669 Accessibility1, Accessibility2, Accessibility3, Accessibility4,
1670 Accessibility5,
1671 ]
1672 .iter()
1673 .position(|c| c == v)
1674 .expect("every DynamicTypeSize is in the table") as u8
1675 },
1676 }
1677
1678 ControlSizeKey {
1680 value: crate::views::ControlSize,
1681 field: b"7SwiftUI11EnvironmentVyAA11ControlSizeOG\0",
1682 value_type: b"7SwiftUI11ControlSizeO",
1683 symbols: (env_control_size_getter, env_control_size_setter, env_control_size_descriptor),
1684 bytes: 1,
1685 decode: |b| {
1686 use crate::views::ControlSize::*;
1687 [Mini, Small, Regular, Large, ExtraLarge][(b[0] as usize).min(4)]
1688 },
1689 encode: |v| {
1690 use crate::views::ControlSize::*;
1691 [Mini, Small, Regular, Large, ExtraLarge]
1692 .iter()
1693 .position(|c| c == v)
1694 .expect("every ControlSize is in the table") as u8
1695 },
1696 }
1697
1698 IsLuminanceReducedKey {
1701 value: bool,
1702 field: b"7SwiftUI11EnvironmentVySbG\0",
1703 value_type: b"Sb",
1704 symbols: (
1705 env_luminance_reduced_getter,
1706 env_luminance_reduced_setter,
1707 env_luminance_reduced_descriptor
1708 ),
1709 bytes: 1,
1710 decode: |b| b[0] != 0,
1711 encode: |v| u8::from(*v),
1712 }
1713}
1714
1715unsafe fn environment_init(key_path: u64, bytes: usize) -> Vec<u8> {
1725 unsafe {
1726 swift_runtime_sys::RuntimeRaw::swift_retain(key_path as *mut c_void);
1727 let mut out = vec![0u8; bytes];
1728 core::arch::asm!("blr {f}", f = in(reg) resolve::environment_init(),
1729 in("x8") out.as_mut_ptr(),
1730 in("x0") key_path,
1731 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
1732 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
1733 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
1734 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
1735 lateout("lr") _, lateout("x20") _, lateout("x21") _, clobber_abi("C"),
1736 );
1737 out
1738 }
1739}
1740
1741unsafe fn environment_get<K: EnvKey>(field: *const u8, env_meta: *const c_void) -> K::Value {
1744 unsafe {
1745 let mut buf = vec![0u8; K::buffer_bytes()];
1746 core::arch::asm!("blr {f}", f = in(reg) resolve::environment_wrapped_get(),
1747 in("x8") buf.as_mut_ptr(),
1748 in("x0") env_meta,
1749 in("x20") field,
1750 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
1751 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
1752 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
1753 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
1754 lateout("lr") _, lateout("x21") _, clobber_abi("C"),
1755 );
1756 K::decode(&buf)
1757 }
1758}
1759
1760struct EnvInstance {
1761 render: Box<dyn Fn(*const u8, *const c_void) -> ViewHandle + Send>,
1762 env_offset: usize,
1767 env_meta: usize,
1768 runs: usize,
1769}
1770
1771static ENVS: std::sync::Mutex<Option<std::collections::HashMap<i64, EnvInstance>>> =
1772 std::sync::Mutex::new(None);
1773
1774fn with_envs<R>(f: impl FnOnce(&mut std::collections::HashMap<i64, EnvInstance>) -> R) -> R {
1775 let mut g = ENVS.lock().expect("environment registry poisoned");
1776 f(g.get_or_insert_with(std::collections::HashMap::new))
1777}
1778
1779core::arch::global_asm!(
1780 ".p2align 2",
1781 ".globl _rswift_env_body_thunk",
1782 "_rswift_env_body_thunk:",
1783 "mov x1, x20",
1784 "mov x0, x8",
1785 "b _rswift_env_body_getter",
1786);
1787
1788unsafe extern "C" {
1789 #[link_name = "rswift_env_body_thunk"]
1790 fn env_body_thunk();
1791}
1792
1793#[unsafe(no_mangle)]
1794unsafe extern "C" fn rswift_env_body_getter(out: *mut u8, this: *const u8) {
1795 unsafe {
1796 let id = *(this as *const i64);
1801 let view = with_envs(|m| {
1802 let inst = m.get_mut(&id)?;
1803 inst.runs += 1;
1804 let (off, meta) = (inst.env_offset, inst.env_meta as *const c_void);
1805 Some((inst.render)(this.add(off), meta))
1806 });
1807 *(out as *mut u64) = view.unwrap_or_else(crate::views::empty_view).into_anyview_word();
1808 }
1809}
1810
1811pub struct EnvironmentView<K: EnvKey> {
1825 pub metadata: *const c_void,
1826 pub witness_table: *const c_void,
1827 value: Vec<u8>,
1828 pub id: i64,
1829 marker: core::marker::PhantomData<fn() -> K>,
1830}
1831
1832impl<K: EnvKey> EnvironmentView<K> {
1833 pub fn new(builder: impl Fn(K::Value) -> ViewHandle + Send + 'static) -> Self {
1835 unsafe {
1836 let id = NEXT_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
1837 with_envs(|m| {
1838 m.insert(
1839 id,
1840 EnvInstance {
1841 render: Box::new(move |field, meta| {
1842 builder(environment_get::<K>(field, meta))
1843 }),
1844 env_offset: 0,
1845 env_meta: 0,
1846 runs: 0,
1847 },
1848 )
1849 });
1850 let field_meta = abi::resolve_type_by_mangled_name(
1851 &K::field_type()[..K::field_type().len() - 1],
1852 );
1853 assert!(!field_meta.is_null(), "Environment<V> metadata");
1854 let (metadata, witness_table) = emit_type(
1855 b"RustEnv\0",
1856 b"6rswift7RustEnvV\0",
1857 &[
1858 FieldSpec { mangled_type: b"Si\0", name: b"id\0", meta: resolve::int_meta() },
1859 FieldSpec {
1860 mangled_type: K::field_type(),
1861 name: b"_value\0",
1862 meta: field_meta,
1863 },
1864 ],
1865 env_body_thunk as *const c_void,
1866 );
1867 let env_off = field_offset(metadata, 1);
1868 debug_assert_eq!(field_offset(metadata, 0), 0, "the id must be field 0");
1869 with_envs(|m| {
1870 if let Some(inst) = m.get_mut(&id) {
1871 inst.env_offset = env_off;
1872 inst.env_meta = field_meta as usize;
1873 }
1874 });
1875
1876 let mut value = vec![0u8; instance_bytes(metadata)];
1879 let env = environment_init(K::key_path(), abi::type_bytes(field_meta));
1880 value[..8].copy_from_slice(&id.to_le_bytes());
1881 value[env_off..env_off + env.len()].copy_from_slice(&env);
1882 Self { metadata, witness_table, value, id, marker: core::marker::PhantomData }
1883 }
1884 }
1885
1886 pub fn runs(&self) -> usize {
1888 with_envs(|m| m.get(&self.id).map_or(0, |i| i.runs))
1889 }
1890
1891 pub fn as_view(&self) -> ViewHandle {
1893 unsafe { copy_as_view(&self.value, self.metadata, self.witness_table) }
1894 }
1895}
1896
1897pub trait StateValue: StoredValue {
1904 fn state_field_type() -> &'static [u8];
1906}
1907
1908impl StateValue for bool {
1909 fn state_field_type() -> &'static [u8] {
1910 b"7SwiftUI5StateVySbG\0"
1911 }
1912}
1913impl StateValue for i64 {
1914 fn state_field_type() -> &'static [u8] {
1915 b"7SwiftUI5StateVySiG\0"
1916 }
1917}
1918impl StateValue for f64 {
1919 fn state_field_type() -> &'static [u8] {
1920 b"7SwiftUI5StateVySdG\0"
1921 }
1922}
1923impl StateValue for String {
1924 fn state_field_type() -> &'static [u8] {
1925 b"7SwiftUI5StateVySSG\0"
1926 }
1927}
1928
1929unsafe fn state_box_offset(state_meta: *const c_void) -> usize {
1931 unsafe { abi::type_size(state_meta).saturating_sub(8) }
1932}
1933
1934unsafe fn state_value_of<T: StateValue>(field: *const u8, state_meta: *const c_void) -> T {
1937 unsafe {
1938 let mut buf = vec![0u8; T::buffer_bytes()];
1939 core::arch::asm!("blr {f}", f = in(reg) resolve::state_wrapped_get(),
1940 in("x8") buf.as_mut_ptr(),
1941 in("x0") state_meta,
1942 in("x20") field,
1943 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
1944 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
1945 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
1946 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
1947 lateout("lr") _, lateout("x21") _, clobber_abi("C"),
1948 );
1949 T::decode(&buf)
1950 }
1951}
1952
1953
1954unsafe fn state_binding_bytes(
1957 field: *const u8,
1958 state_meta: *const c_void,
1959 bytes: usize,
1960) -> Vec<u8> {
1961 unsafe {
1962 let mut out = vec![0u8; bytes];
1963 core::arch::asm!("blr {f}", f = in(reg) resolve::state_projected_get(),
1964 in("x8") out.as_mut_ptr(),
1965 in("x0") state_meta,
1966 in("x20") field,
1967 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
1968 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
1969 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
1970 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
1971 lateout("lr") _, lateout("x21") _, clobber_abi("C"),
1972 );
1973 out
1974 }
1975}
1976
1977unsafe fn binding_meta<T: StoredValue>() -> *const c_void {
1978 unsafe {
1979 let m = abi::resolve_type_by_mangled_name(
1980 mangle::bound("7SwiftUI7BindingV", &[T::mangled()]).as_bytes(),
1981 );
1982 assert!(!m.is_null(), "Binding metadata");
1983 m
1984 }
1985}
1986
1987unsafe fn binding_set_of<T: StoredValue>(binding: &mut [u8], value: &T) {
1990 unsafe {
1991 let mut v = value.encode();
1992 core::arch::asm!("blr {f}", f = in(reg) resolve::binding_wrapped_set(),
1993 in("x0") v.as_mut_ptr(),
1994 in("x1") binding_meta::<T>(),
1995 in("x20") binding.as_mut_ptr(),
1996 lateout("x2") _, lateout("x3") _, lateout("x4") _, lateout("x5") _,
1997 lateout("x6") _, lateout("x7") _, lateout("x8") _, lateout("x9") _,
1998 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
1999 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
2000 lateout("lr") _, lateout("x21") _, clobber_abi("C"),
2001 );
2002 }
2003}
2004
2005fn prop_name(i: usize) -> &'static [u8] {
2024 Box::leak(format!("_p{i}\0").into_bytes().into_boxed_slice())
2027}
2028
2029#[derive(Clone, Copy, PartialEq, Eq)]
2030enum PropKind {
2031 State,
2032 Stored,
2033 Env,
2034 Focus,
2035}
2036
2037struct PropSpec {
2038 field_type: &'static [u8],
2039 meta: *const c_void,
2040 binding_bytes: usize,
2043 init: Vec<u8>,
2046 kind: PropKind,
2047}
2048
2049#[derive(Clone, Copy)]
2051struct PropSlot {
2052 offset: usize,
2053 meta: usize,
2054 binding_bytes: usize,
2055 kind: PropKind,
2056}
2057
2058#[derive(Debug)]
2067pub struct StateProp<T> {
2068 index: usize,
2069 marker: core::marker::PhantomData<fn() -> T>,
2070}
2071
2072#[derive(Debug)]
2074pub struct StoredProp<T> {
2075 index: usize,
2076 marker: core::marker::PhantomData<fn() -> T>,
2077}
2078
2079#[derive(Debug)]
2081pub struct EnvProp<K> {
2082 index: usize,
2083 marker: core::marker::PhantomData<fn() -> K>,
2084}
2085
2086#[derive(Clone, Copy, Debug)]
2088pub struct FocusProp {
2089 index: usize,
2090}
2091
2092pub struct Props {
2098 this: *const u8,
2099 slots: Vec<PropSlot>,
2100}
2101
2102impl Props {
2103 fn slot(&self, i: usize, want: PropKind, what: &str) -> PropSlot {
2104 let s = *self.slots.get(i).unwrap_or_else(|| {
2105 panic!("no property at index {i}; the view has {}", self.slots.len())
2106 });
2107 assert!(s.kind == want, "property {i} is not {what}");
2108 s
2109 }
2110
2111 pub fn state<T: StateValue + Default>(&self, prop: StateProp<T>) -> T {
2117 let s = self.slot(prop.index, PropKind::State, "@State");
2118 unsafe {
2119 let meta = s.meta as *const c_void;
2120 if *(self.this.add(s.offset + state_box_offset(meta)) as *const u64) == 0 {
2121 T::default()
2122 } else {
2123 state_value_of::<T>(self.this.add(s.offset), meta)
2124 }
2125 }
2126 }
2127
2128 pub fn stored<T: StoredValue>(&self, prop: StoredProp<T>) -> T {
2130 let s = self.slot(prop.index, PropKind::Stored, "@AppStorage");
2131 unsafe { app_storage_get::<T>(*(self.this.add(s.offset) as *const u64)) }
2132 }
2133
2134 pub fn focus(&self, prop: FocusProp) -> bool {
2136 let s = self.slot(prop.index, PropKind::Focus, "@FocusState");
2137 unsafe { focus_get(self.this.add(s.offset), s.meta as *const c_void) }
2138 }
2139
2140 pub fn focus_projection(&self, prop: FocusProp) -> [u64; 3] {
2143 let s = self.slot(prop.index, PropKind::Focus, "@FocusState");
2144 unsafe { focus_projection(self.this.add(s.offset), s.meta as *const c_void) }
2145 }
2146
2147 pub fn env<K: EnvKey>(&self, prop: EnvProp<K>) -> K::Value {
2149 let s = self.slot(prop.index, PropKind::Env, "@Environment");
2150 unsafe { environment_get::<K>(self.this.add(s.offset), s.meta as *const c_void) }
2151 }
2152}
2153
2154struct ComposedInstance {
2155 body: Box<dyn Fn(&Props) -> ViewHandle + Send>,
2156 slots: Vec<PropSlot>,
2157 bindings: std::collections::HashMap<usize, Vec<u8>>,
2160 focus: std::collections::HashMap<usize, [u64; 3]>,
2163 runs: usize,
2164}
2165
2166static COMPOSED: std::sync::Mutex<Option<std::collections::HashMap<i64, ComposedInstance>>> =
2167 std::sync::Mutex::new(None);
2168
2169fn with_composed<R>(
2170 f: impl FnOnce(&mut std::collections::HashMap<i64, ComposedInstance>) -> R,
2171) -> R {
2172 let mut g = COMPOSED.lock().expect("composed registry poisoned");
2173 f(g.get_or_insert_with(std::collections::HashMap::new))
2174}
2175
2176core::arch::global_asm!(
2177 ".p2align 2",
2178 ".globl _rswift_composed_body_thunk",
2179 "_rswift_composed_body_thunk:",
2180 "mov x1, x20",
2181 "mov x0, x8",
2182 "b _rswift_composed_body_getter",
2183);
2184
2185unsafe extern "C" {
2186 #[link_name = "rswift_composed_body_thunk"]
2187 fn composed_body_thunk();
2188}
2189
2190#[unsafe(no_mangle)]
2191unsafe extern "C" fn rswift_composed_body_getter(out: *mut u8, this: *const u8) {
2192 unsafe {
2193 let id = *(this as *const i64);
2195 let view = with_composed(|m| {
2196 let inst = m.get_mut(&id)?;
2197 inst.runs += 1;
2198 for (i, s) in inst.slots.iter().enumerate() {
2201 if s.kind == PropKind::State && !inst.bindings.contains_key(&i) {
2202 let meta = s.meta as *const c_void;
2203 if *(this.add(s.offset + state_box_offset(meta)) as *const u64) != 0 {
2204 inst.bindings
2208 .insert(i, state_binding_bytes(this.add(s.offset), meta, s.binding_bytes));
2209 }
2210 }
2211 }
2212 for (i, s) in inst.slots.iter().enumerate() {
2213 if s.kind == PropKind::Focus && !inst.focus.contains_key(&i) {
2214 inst.focus
2215 .insert(i, focus_projection(this.add(s.offset), s.meta as *const c_void));
2216 }
2217 }
2218 let props = Props { this, slots: inst.slots.clone() };
2219 Some((inst.body)(&props))
2220 });
2221 *(out as *mut u64) = view.unwrap_or_else(crate::views::empty_view).into_anyview_word();
2222 }
2223}
2224
2225pub struct ComposedBuilder {
2229 specs: Vec<PropSpec>,
2230}
2231
2232impl Default for ComposedBuilder {
2233 fn default() -> Self {
2234 Self::new()
2235 }
2236}
2237
2238impl ComposedBuilder {
2239 pub fn new() -> Self {
2240 Self { specs: Vec::new() }
2241 }
2242
2243 pub fn state<T: StateValue>(&mut self, initial: T) -> StateProp<T> {
2247 unsafe {
2248 let ft = T::state_field_type();
2249 let meta = abi::resolve_type_by_mangled_name(&ft[..ft.len() - 1]);
2250 assert!(!meta.is_null(), "State<T> metadata");
2251 let mut init = vec![0u8; abi::type_bytes(meta)];
2253 let bytes = initial.encode();
2254 init[..bytes.len()].copy_from_slice(&bytes);
2255 self.specs.push(PropSpec {
2256 field_type: ft,
2257 meta,
2258 binding_bytes: abi::type_bytes(binding_meta::<T>()),
2259 init,
2260 kind: PropKind::State,
2261 });
2262 StateProp { index: self.specs.len() - 1, marker: core::marker::PhantomData }
2263 }
2264 }
2265
2266 pub fn app_storage<T: StoredValue>(&mut self, key: &str, default: T) -> StoredProp<T> {
2268 unsafe {
2269 let ft = T::field_type();
2270 let meta = abi::resolve_type_by_mangled_name(&ft[..ft.len() - 1]);
2271 assert!(!meta.is_null(), "AppStorage<T> metadata");
2272 self.specs.push(PropSpec {
2273 field_type: ft,
2274 meta,
2275 binding_bytes: 0,
2276 init: default.init_storage(key).to_le_bytes().to_vec(),
2277 kind: PropKind::Stored,
2278 });
2279 StoredProp { index: self.specs.len() - 1, marker: core::marker::PhantomData }
2280 }
2281 }
2282
2283 pub fn focus_state(&mut self) -> FocusProp {
2289 unsafe {
2290 let meta = focus_state_meta();
2291 self.specs.push(PropSpec {
2292 field_type: FOCUS_STATE_BOOL,
2293 meta,
2294 binding_bytes: 0,
2295 init: focus_state_init(meta),
2296 kind: PropKind::Focus,
2297 });
2298 FocusProp { index: self.specs.len() - 1 }
2299 }
2300 }
2301
2302 pub fn environment<K: EnvKey>(&mut self) -> EnvProp<K> {
2304 unsafe {
2305 let ft = K::field_type();
2306 let meta = abi::resolve_type_by_mangled_name(&ft[..ft.len() - 1]);
2307 assert!(!meta.is_null(), "Environment<V> metadata");
2308 self.specs.push(PropSpec {
2309 field_type: ft,
2310 meta,
2311 binding_bytes: 0,
2312 init: environment_init(K::key_path(), abi::type_bytes(meta)),
2313 kind: PropKind::Env,
2314 });
2315 EnvProp { index: self.specs.len() - 1, marker: core::marker::PhantomData }
2316 }
2317 }
2318
2319 pub fn build(self, body: impl Fn(&Props) -> ViewHandle + Send + 'static) -> ComposedView {
2321 assert!(!self.specs.is_empty(), "a composed view needs at least one property");
2322 unsafe {
2323 let id = NEXT_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
2324
2325 let mut fields = vec![FieldSpec {
2328 mangled_type: b"Si\0",
2329 name: b"id\0",
2330 meta: resolve::int_meta(),
2331 }];
2332 for (i, spec) in self.specs.iter().enumerate() {
2333 fields.push(FieldSpec {
2334 mangled_type: spec.field_type,
2335 name: prop_name(i),
2336 meta: spec.meta,
2337 });
2338 }
2339 let (metadata, witness_table) = emit_type(
2340 b"RustComposed\0",
2341 b"6rswift12RustComposedV\0",
2342 &fields,
2343 composed_body_thunk as *const c_void,
2344 );
2345 debug_assert_eq!(field_offset(metadata, 0), 0, "the id must be field 0");
2346
2347 let mut value = vec![0u8; instance_bytes(metadata)];
2348 value[..8].copy_from_slice(&id.to_le_bytes());
2349 let mut slots = Vec::with_capacity(self.specs.len());
2350 for (i, spec) in self.specs.iter().enumerate() {
2351 let off = field_offset(metadata, i + 1);
2352 value[off..off + spec.init.len()].copy_from_slice(&spec.init);
2353 slots.push(PropSlot {
2354 offset: off,
2355 meta: spec.meta as usize,
2356 binding_bytes: spec.binding_bytes,
2357 kind: spec.kind,
2358 });
2359 }
2360
2361 with_composed(|m| {
2362 m.insert(
2363 id,
2364 ComposedInstance {
2365 body: Box::new(body),
2366 slots: slots.clone(),
2367 bindings: std::collections::HashMap::new(),
2368 focus: std::collections::HashMap::new(),
2369 runs: 0,
2370 },
2371 )
2372 });
2373 ComposedView { metadata, witness_table, value, id, slots }
2374 }
2375 }
2376}
2377
2378pub struct ComposedView {
2412 pub metadata: *const c_void,
2413 pub witness_table: *const c_void,
2414 value: Vec<u8>,
2415 pub id: i64,
2416 slots: Vec<PropSlot>,
2417}
2418
2419impl ComposedView {
2420 pub fn set_state<T: StateValue>(&self, prop: StateProp<T>, value: T) -> bool {
2426 let i = prop.index;
2427 let binding = with_composed(|m| m.get(&self.id).and_then(|c| c.bindings.get(&i).cloned()));
2428 let Some(mut binding) = binding else { return false };
2429 unsafe { binding_set_of::<T>(&mut binding, &value) };
2430 true
2431 }
2432
2433 fn stored_location(&self, i: usize) -> u64 {
2434 let s = self.slots[i];
2435 u64::from_le_bytes(self.value[s.offset..s.offset + 8].try_into().expect("location"))
2436 }
2437
2438 pub fn stored<T: StoredValue>(&self, prop: StoredProp<T>) -> T {
2440 unsafe { app_storage_get::<T>(self.stored_location(prop.index)) }
2441 }
2442
2443 pub fn set_stored<T: StoredValue>(&self, prop: StoredProp<T>, value: T) {
2445 unsafe { app_storage_set::<T>(self.stored_location(prop.index), &value) }
2446 }
2447
2448 pub fn set_focus(&self, prop: FocusProp, value: bool) -> bool {
2455 let i = prop.index;
2456 let proj = with_composed(|m| m.get(&self.id).and_then(|c| c.focus.get(&i).copied()));
2457 let Some(mut proj) = proj else { return false };
2458 unsafe { focus_binding_set(&mut proj, value) };
2459 true
2460 }
2461
2462 pub fn focus(&self, prop: FocusProp) -> bool {
2465 let i = prop.index;
2466 let proj = with_composed(|m| m.get(&self.id).and_then(|c| c.focus.get(&i).copied()));
2467 match proj {
2468 Some(p) => unsafe { focus_binding_get(&p) },
2469 None => false,
2470 }
2471 }
2472
2473
2474
2475 pub fn runs(&self) -> usize {
2477 with_composed(|m| m.get(&self.id).map_or(0, |c| c.runs))
2478 }
2479
2480 pub fn as_view(&self) -> ViewHandle {
2482 unsafe { copy_as_view(&self.value, self.metadata, self.witness_table) }
2483 }
2484}
2485
2486impl Drop for StatefulView {
2487 fn drop(&mut self) {
2488 unsafe { destroy_instance(&mut self.value, self.metadata) };
2489 }
2490}
2491
2492impl<T: StoredValue> Drop for StoredView<T> {
2493 fn drop(&mut self) {
2494 unsafe { destroy_instance(&mut self.value, self.metadata) };
2495 }
2496}
2497
2498impl<K: EnvKey> Drop for EnvironmentView<K> {
2499 fn drop(&mut self) {
2500 unsafe { destroy_instance(&mut self.value, self.metadata) };
2501 }
2502}
2503
2504impl Drop for ComposedView {
2505 fn drop(&mut self) {
2506 unsafe { destroy_instance(&mut self.value, self.metadata) };
2507 }
2508}
2509
2510const FOCUS_STATE_BOOL: &[u8] = b"7SwiftUI10FocusStateVySbG\0";
2532
2533unsafe fn focus_state_meta() -> *const c_void {
2534 unsafe {
2535 let m = abi::resolve_type_by_mangled_name(&FOCUS_STATE_BOOL[..FOCUS_STATE_BOOL.len() - 1]);
2536 assert!(!m.is_null(), "FocusState<Bool> metadata");
2537 m
2538 }
2539}
2540
2541unsafe fn focus_state_init(meta: *const c_void) -> Vec<u8> {
2546 unsafe {
2547 let mut out = vec![0u8; abi::type_bytes(meta)];
2548 core::arch::asm!("blr {f}", f = in(reg) resolve::focus_state_bool_init(),
2549 in("x8") out.as_mut_ptr(),
2550 in("x20") meta,
2551 lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
2552 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
2553 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
2554 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
2555 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
2556 );
2557 out
2558 }
2559}
2560
2561unsafe fn focus_get(field: *const u8, meta: *const c_void) -> bool {
2563 let mut out: u8 = 0;
2564 unsafe {
2565 core::arch::asm!("blr {f}", f = in(reg) resolve::focus_state_wrapped_get(),
2566 in("x8") &mut out as *mut u8,
2567 in("x0") meta,
2568 in("x20") field,
2569 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
2570 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
2571 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
2572 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
2573 lateout("lr") _, lateout("x21") _, clobber_abi("C"),
2574 );
2575 }
2576 out != 0
2577}
2578
2579
2580unsafe fn focus_binding_meta() -> *const c_void {
2581 unsafe {
2582 let m = abi::resolve_type_by_mangled_name(b"7SwiftUI10FocusStateV7BindingVySb_G");
2583 assert!(!m.is_null(), "FocusState<Bool>.Binding metadata");
2584 m
2585 }
2586}
2587
2588unsafe fn focus_binding_set(projection: &mut [u64; 3], value: bool) {
2596 unsafe {
2597 let mut v = u8::from(value);
2598 core::arch::asm!("blr {f}", f = in(reg) resolve::focus_binding_wrapped_set(),
2599 in("x0") &mut v as *mut u8,
2600 in("x1") focus_binding_meta(),
2601 in("x20") projection.as_mut_ptr(),
2602 lateout("x2") _, lateout("x3") _, lateout("x4") _, lateout("x5") _,
2603 lateout("x6") _, lateout("x7") _, lateout("x8") _, lateout("x9") _,
2604 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
2605 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
2606 lateout("lr") _, lateout("x21") _, clobber_abi("C"),
2607 );
2608 }
2609}
2610
2611unsafe fn focus_binding_get(projection: &[u64; 3]) -> bool {
2613 let mut out: u8 = 0;
2614 unsafe {
2615 core::arch::asm!("blr {f}", f = in(reg) resolve::focus_binding_wrapped_get(),
2616 in("x8") &mut out as *mut u8,
2617 in("x0") focus_binding_meta(),
2618 in("x20") projection.as_ptr(),
2619 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
2620 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
2621 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
2622 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
2623 lateout("lr") _, lateout("x21") _, clobber_abi("C"),
2624 );
2625 }
2626 out != 0
2627}
2628
2629unsafe fn focus_projection(field: *const u8, meta: *const c_void) -> [u64; 3] {
2631 unsafe {
2632 let mut out = [0u64; 3];
2633 core::arch::asm!("blr {f}", f = in(reg) resolve::focus_state_projected(),
2634 in("x8") out.as_mut_ptr(),
2635 in("x0") meta,
2636 in("x20") field,
2637 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
2638 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
2639 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
2640 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
2641 lateout("lr") _, lateout("x21") _, clobber_abi("C"),
2642 );
2643 out
2644 }
2645}
2646
2647impl<T> Clone for StateProp<T> {
2652 fn clone(&self) -> Self {
2653 *self
2654 }
2655}
2656impl<T> Copy for StateProp<T> {}
2657impl<T> Clone for StoredProp<T> {
2658 fn clone(&self) -> Self {
2659 *self
2660 }
2661}
2662impl<T> Copy for StoredProp<T> {}
2663impl<K> Clone for EnvProp<K> {
2664 fn clone(&self) -> Self {
2665 *self
2666 }
2667}
2668impl<K> Copy for EnvProp<K> {}