1use super::{wrap_owned, ViewHandle};
45use crate::conformance::{synthesize, Conformance, Protocol, Witness};
46use crate::keypath;
47use crate::mangle::{self, swift_type};
48use crate::resolve;
49use core::ffi::c_void;
50use std::sync::{Mutex, OnceLock};
51
52pub trait KeyValue: Clone + Send + Sync + 'static {
71 fn mangled() -> &'static str;
73
74 fn metadata() -> *const c_void;
76
77 unsafe fn write(&self, out: *mut u8);
82
83 unsafe fn read(from: *const u8) -> Self;
88}
89
90pub trait IntoKeyValue<T: KeyValue> {
97 fn into_key_value(self) -> T;
99}
100
101impl<T: KeyValue> IntoKeyValue<T> for T {
102 fn into_key_value(self) -> T {
103 self
104 }
105}
106
107impl IntoKeyValue<String> for &str {
108 fn into_key_value(self) -> String {
109 self.to_string()
110 }
111}
112
113impl KeyValue for i64 {
114 fn mangled() -> &'static str {
115 crate::mangle::INT
116 }
117 fn metadata() -> *const c_void {
118 resolve::int_meta()
119 }
120 unsafe fn write(&self, out: *mut u8) {
121 unsafe { *(out as *mut i64) = *self };
122 }
123 unsafe fn read(from: *const u8) -> Self {
124 unsafe { *(from as *const i64) }
125 }
126}
127
128impl KeyValue for f64 {
129 fn mangled() -> &'static str {
130 crate::mangle::DOUBLE
131 }
132 fn metadata() -> *const c_void {
133 resolve::double_meta()
134 }
135 unsafe fn write(&self, out: *mut u8) {
136 unsafe { *(out as *mut f64) = *self };
137 }
138 unsafe fn read(from: *const u8) -> Self {
139 unsafe { *(from as *const f64) }
140 }
141}
142
143impl KeyValue for bool {
144 fn mangled() -> &'static str {
145 crate::mangle::BOOL
146 }
147 fn metadata() -> *const c_void {
148 resolve::bool_meta()
149 }
150 unsafe fn write(&self, out: *mut u8) {
151 unsafe { *out = u8::from(*self) };
152 }
153 unsafe fn read(from: *const u8) -> Self {
154 unsafe { *from & 1 != 0 }
155 }
156}
157
158impl KeyValue for String {
159 fn mangled() -> &'static str {
160 crate::mangle::STRING
161 }
162 fn metadata() -> *const c_void {
163 resolve::string_meta()
164 }
165 unsafe fn write(&self, out: *mut u8) {
166 let bytes = unsafe { crate::abi::swift_string(self) };
168 unsafe { core::ptr::copy_nonoverlapping(bytes.as_ptr(), out, 16) };
169 }
170 unsafe fn read(from: *const u8) -> Self {
171 let mut bytes = [0u8; 16];
172 unsafe { core::ptr::copy_nonoverlapping(from, bytes.as_mut_ptr(), 16) };
173 unsafe { crate::abi::read_swift_string(bytes) }
174 }
175}
176
177unsafe fn read_default<T: KeyValue>(
189 table: *const c_void,
190 slot: usize,
191 key_meta: *const c_void,
192) -> T {
193 unsafe {
194 let witness = *(table as *const *const c_void).add(slot + 1);
195 let mut out = vec![0u8; crate::abi::type_bytes(T::metadata())];
196 core::arch::asm!("blr {f}", f = in(reg) witness,
197 in("x8") out.as_mut_ptr(),
198 in("x20") key_meta,
199 lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
200 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
201 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
202 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
203 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
204 );
205 let value = T::read(out.as_ptr());
206 crate::abi::type_destroy(T::metadata(), out.as_mut_ptr());
207 value
208 }
209}
210
211pub struct FocusKey<T: KeyValue = i64> {
214 slot: usize,
221 key_path: u64,
222 value: core::marker::PhantomData<fn() -> T>,
223}
224
225impl<T: KeyValue> FocusKey<T> {
226 #[doc(hidden)]
233 pub fn key_path_for_test(&self) -> u64 {
234 self.key_path
235 }
236
237 #[doc(hidden)]
239 pub fn parts_for_test(&self) -> (usize, usize) {
240 let r = registry().lock().expect("focus key registry");
241 let e = r[self.slot].as_ref().expect("a registered focus key");
242 (e.key_meta, e.key_wt)
243 }
244}
245
246struct Registered {
253 key_meta: usize,
254 key_wt: usize,
255 key_path: u64,
256}
257
258fn registry() -> &'static Mutex<Vec<Option<Registered>>> {
259 static R: OnceLock<Mutex<Vec<Option<Registered>>>> = OnceLock::new();
260 R.get_or_init(|| Mutex::new((0..keypath::VALUE_SLOTS).map(|_| None).collect()))
261}
262
263fn named() -> &'static Mutex<Vec<(String, usize)>> {
265 static N: OnceLock<Mutex<Vec<(String, usize)>>> = OnceLock::new();
266 N.get_or_init(|| Mutex::new(Vec::new()))
267}
268
269pub fn focus_key<T: KeyValue>(name: &str) -> FocusKey<T> {
281 let mut names = named().lock().expect("focus key names");
282 if let Some(&(_, slot)) = names.iter().find(|(n, _)| n == name) {
283 let key_path = registry().lock().expect("focus key registry")[slot]
284 .as_ref()
285 .expect("a registered focus key")
286 .key_path;
287 return FocusKey { slot, key_path, value: core::marker::PhantomData };
288 }
289
290 let slot = keypath::next_value_slot();
291 names.push((name.to_string(), slot));
292
293 unsafe {
294 let type_name: &'static [u8] = leak_cstr(&format!("RustFocusKey{slot}"));
298 let mangled: &'static [u8] =
299 leak_cstr(&format!("6rswift{}RustFocusKey{slot}V", 12 + digits(slot)));
300 let (descriptor, key_meta) = crate::state::emit_int_carrier(type_name, mangled);
301
302 let protocol = Protocol::from_symbol(c"$s7SwiftUI15FocusedValueKeyMp");
303 assert_eq!(
304 protocol.requirement_count(),
305 1,
306 "FocusedValueKey changed shape — it used to be one associated type",
307 );
308 let conformance: &'static Conformance = Box::leak(Box::new(synthesize(
311 &protocol,
312 descriptor,
313 &[Witness::Metadata(T::metadata())],
314 )));
315 let key_wt = conformance.witness_table();
316
317 let (get, set, get_target, set_target) = keypath::value_thunks(slot);
318 *get_target = focus_get as *const c_void;
319 *set_target = focus_set as *const c_void;
320 registry().lock().expect("focus key registry")[slot] = Some(Registered {
323 key_meta: key_meta as usize,
324 key_wt: key_wt as usize,
325 key_path: 0,
326 });
327 let key_path = keypath::build_writable_computed(
328 keypath::value_slot(slot),
329 swift_type!(SwiftUI.FocusedValues).as_bytes(),
330 mangle::optional(T::mangled()).as_bytes(),
331 get,
332 set,
333 );
334 swift_runtime_sys::RuntimeRaw::swift_retain(key_path as *mut c_void);
337 registry().lock().expect("focus key registry")[slot]
338 .as_mut()
339 .expect("just registered")
340 .key_path = key_path;
341
342 FocusKey { slot, key_path, value: core::marker::PhantomData }
343 }
344}
345
346static GETS: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
356static SETS: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
357
358#[doc(hidden)]
360pub fn focus_accessor_counts() -> (usize, usize) {
361 use std::sync::atomic::Ordering::Relaxed;
362 (GETS.load(Relaxed), SETS.load(Relaxed))
363}
364
365fn digits(n: usize) -> usize {
367 if n < 10 {
368 1
369 } else if n < 100 {
370 2
371 } else {
372 3
373 }
374}
375
376fn leak_cstr(s: &str) -> &'static [u8] {
381 let mut bytes = s.as_bytes().to_vec();
382 bytes.push(0);
383 Box::leak(bytes.into_boxed_slice())
384}
385
386unsafe extern "C" fn focus_get(out: *mut u8, root: *const c_void, index: u64) {
393 GETS.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
394 let (meta, wt) = {
395 let r = registry().lock().expect("focus key registry");
396 let e = r[index as usize].as_ref().expect("a registered focus key");
397 (e.key_meta as *const c_void, e.key_wt as *const c_void)
398 };
399 unsafe {
400 core::arch::asm!("blr {f}", f = in(reg) resolve::focused_values_get(),
404 in("x0") meta,
405 in("x1") meta,
406 in("x2") wt,
407 in("x8") out,
408 in("x20") root,
409 lateout("x3") _, lateout("x4") _, lateout("x5") _, lateout("x6") _,
410 lateout("x7") _,
411 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
412 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
413 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
414 );
415 }
416}
417
418unsafe extern "C" fn focus_set(value: *const u8, root: *mut c_void, index: u64) {
423 SETS.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
424 let (meta, wt) = {
425 let r = registry().lock().expect("focus key registry");
426 let e = r[index as usize].as_ref().expect("a registered focus key");
427 (e.key_meta as *const c_void, e.key_wt as *const c_void)
428 };
429 unsafe {
430 core::arch::asm!("blr {f}", f = in(reg) resolve::focused_values_set(),
433 in("x0") value,
434 in("x1") meta,
435 in("x2") meta,
436 in("x3") wt,
437 in("x20") root,
438 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
439 lateout("x8") _,
440 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
441 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
442 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
443 );
444 }
445}
446
447pub fn focused_scene_value<T: KeyValue>(
453 view: &ViewHandle,
454 key: &FocusKey<T>,
455 value: impl IntoKeyValue<T>,
456) -> ViewHandle {
457 unsafe {
458 publish(
459 view,
460 key,
461 value.into_key_value(),
462 resolve::focused_scene_value_fn(),
463 resolve::focused_scene_value_oret(),
464 )
465 }
466}
467
468pub fn focused_value_keyed<T: KeyValue>(
470 view: &ViewHandle,
471 key: &FocusKey<T>,
472 value: impl IntoKeyValue<T>,
473) -> ViewHandle {
474 unsafe {
475 publish(
476 view,
477 key,
478 value.into_key_value(),
479 resolve::focused_value_kp_fn(),
480 resolve::focused_value_kp_oret(),
481 )
482 }
483}
484
485unsafe fn publish<T: KeyValue>(
488 view: &ViewHandle,
489 key: &FocusKey<T>,
490 value: T,
491 f: *const c_void,
492 oret: *const c_void,
493) -> ViewHandle {
494 unsafe {
495 let mut boxed = vec![0u8; crate::abi::type_bytes(T::metadata())];
497 value.write(boxed.as_mut_ptr());
498 swift_runtime_sys::RuntimeRaw::swift_retain(key.key_path as *mut c_void);
502
503 let (meta, wt, size) =
509 super::opaque_result_type(oret, &[view.meta, T::metadata(), view.wt]);
510 let mut result = vec![0u8; size];
511 let this = view.value_ptr();
512 core::arch::asm!("blr {f}", f = in(reg) f,
518 in("x0") key.key_path,
519 in("x1") boxed.as_mut_ptr(),
520 in("x2") view.meta,
521 in("x3") view.wt,
522 in("x8") result.as_mut_ptr(),
523 in("x20") this,
524 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
525 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
526 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
527 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
528 );
529 wrap_owned(result, meta, wt)
530 }
531}
532
533pub struct CustomEnvKey<T: KeyValue = i64> {
556 slot: usize,
557 key_path: u64,
558 value: core::marker::PhantomData<fn() -> T>,
559}
560
561impl<T: KeyValue> CustomEnvKey<T> {
562 #[doc(hidden)]
570 pub fn default_for_test(&self) -> T {
571 let (key_meta, key_wt) = {
572 let r = env_registry().lock().expect("environment key registry");
573 let e = r[self.slot].as_ref().expect("a registered environment key");
574 (e.key_meta as *const c_void, e.key_wt as *const c_void)
575 };
576 unsafe { read_default(key_wt, 1, key_meta) }
578 }
579
580 #[doc(hidden)]
582 pub fn key_path_for_test(&self) -> u64 {
583 self.key_path
584 }
585}
586
587struct EnvRegistered {
594 key_meta: usize,
595 key_wt: usize,
596 key_path: u64,
597 write_default: Box<dyn Fn(*mut u8) + Send + Sync>,
598}
599
600fn env_registry() -> &'static Mutex<Vec<Option<EnvRegistered>>> {
601 static R: OnceLock<Mutex<Vec<Option<EnvRegistered>>>> = OnceLock::new();
602 R.get_or_init(|| Mutex::new((0..keypath::VALUE_SLOTS).map(|_| None).collect()))
603}
604
605fn env_named() -> &'static Mutex<Vec<(String, usize)>> {
607 static N: OnceLock<Mutex<Vec<(String, usize)>>> = OnceLock::new();
608 N.get_or_init(|| Mutex::new(Vec::new()))
609}
610
611fn env_slot_for(meta: *const c_void) -> usize {
617 let r = env_registry().lock().expect("environment key registry");
618 r.iter()
619 .position(|e| e.as_ref().is_some_and(|e| e.key_meta == meta as usize))
620 .unwrap_or_else(|| {
621 panic!("no environment key registered for {}", crate::diag::type_name(meta))
622 })
623}
624
625crate::thunk::runtime_thunk! {
626 fn env_default_thunk = "rswift_env_default" via RSWIFT_ENV_DEFAULT {
628 prologue: ["mov x1, x20", "mov x0, x8"],
629 branch: "br",
630 epilogue: [],
631 }
632}
633
634unsafe extern "C" fn env_default(out: *mut u8, meta: *const c_void) {
640 let slot = env_slot_for(meta);
641 let r = env_registry().lock().expect("environment key registry");
642 (r[slot].as_ref().expect("a registered environment key").write_default)(out);
643}
644
645unsafe extern "C" fn env_get(out: *mut u8, root: *const c_void, index: u64) {
650 let (meta, wt) = {
651 let r = env_registry().lock().expect("environment key registry");
652 let e = r[index as usize].as_ref().expect("a registered environment key");
653 (e.key_meta as *const c_void, e.key_wt as *const c_void)
654 };
655 unsafe {
656 core::arch::asm!("blr {f}", f = in(reg) resolve::environment_values_get(),
657 in("x0") meta,
658 in("x1") meta,
659 in("x2") wt,
660 in("x8") out,
661 in("x20") root,
662 lateout("x3") _, lateout("x4") _, lateout("x5") _, lateout("x6") _,
663 lateout("x7") _,
664 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
665 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
666 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
667 );
668 }
669}
670
671unsafe extern "C" fn env_set(value: *const u8, root: *mut c_void, index: u64) {
676 let (meta, wt) = {
677 let r = env_registry().lock().expect("environment key registry");
678 let e = r[index as usize].as_ref().expect("a registered environment key");
679 (e.key_meta as *const c_void, e.key_wt as *const c_void)
680 };
681 unsafe {
682 core::arch::asm!("blr {f}", f = in(reg) resolve::environment_values_set(),
683 in("x0") value,
684 in("x1") meta,
685 in("x2") meta,
686 in("x3") wt,
687 in("x20") root,
688 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
689 lateout("x8") _,
690 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
691 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
692 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
693 );
694 }
695}
696
697pub fn env_key<T: KeyValue>(name: &str, default: impl IntoKeyValue<T>) -> CustomEnvKey<T> {
707 let default = default.into_key_value();
708 let mut names = env_named().lock().expect("environment key names");
709 if let Some(&(_, slot)) = names.iter().find(|(n, _)| n == name) {
710 let key_path = env_registry().lock().expect("environment key registry")[slot]
711 .as_ref()
712 .expect("a registered environment key")
713 .key_path;
714 return CustomEnvKey { slot, key_path, value: core::marker::PhantomData };
715 }
716
717 let slot = keypath::next_value_slot();
718 names.push((name.to_string(), slot));
719
720 unsafe {
721 let type_name: &'static [u8] = leak_cstr(&format!("RustEnvKey{slot}"));
722 let mangled: &'static [u8] =
723 leak_cstr(&format!("6rswift{}RustEnvKey{slot}V", 10 + digits(slot)));
724 let (descriptor, key_meta) = crate::state::emit_int_carrier(type_name, mangled);
725
726 let protocol = Protocol::from_symbol(c"$s7SwiftUI14EnvironmentKeyMp");
727 assert_eq!(
728 protocol.requirement_count(),
729 3,
730 "EnvironmentKey changed shape — it used to be Value, defaultValue and \
731 one defaulted requirement",
732 );
733 let conformance: &'static Conformance = Box::leak(Box::new(synthesize(
734 &protocol,
735 descriptor,
736 &[
737 Witness::Metadata(T::metadata()),
738 Witness::Function(env_default_thunk as *const c_void),
739 Witness::Default,
740 ],
741 )));
742 let key_wt = conformance.witness_table();
743
744 let (get, set, get_target, set_target) = keypath::value_thunks(slot);
745 *get_target = env_get as *const c_void;
746 *set_target = env_set as *const c_void;
747 RSWIFT_ENV_DEFAULT = env_default as *const c_void;
748 env_registry().lock().expect("environment key registry")[slot] = Some(EnvRegistered {
751 key_meta: key_meta as usize,
752 key_wt: key_wt as usize,
753 key_path: 0,
754 write_default: Box::new(move |out| default.write(out)),
757 });
758
759 let key_path = keypath::build_writable_computed(
760 keypath::value_slot(slot),
761 swift_type!(SwiftUI.EnvironmentValues).as_bytes(),
762 T::mangled().as_bytes(),
763 get,
764 set,
765 );
766 swift_runtime_sys::RuntimeRaw::swift_retain(key_path as *mut c_void);
767 env_registry().lock().expect("environment key registry")[slot]
768 .as_mut()
769 .expect("just registered")
770 .key_path = key_path;
771
772 CustomEnvKey { slot, key_path, value: core::marker::PhantomData }
773 }
774}
775
776pub fn environment_value<T: KeyValue>(
778 view: &ViewHandle,
779 key: &CustomEnvKey<T>,
780 value: impl IntoKeyValue<T>,
781) -> ViewHandle {
782 let value = value.into_key_value();
783 unsafe {
784 let _ = key.slot;
785 let mut boxed = vec![0u8; crate::abi::type_bytes(T::metadata()).max(1)];
788 value.write(boxed.as_mut_ptr());
789 swift_runtime_sys::RuntimeRaw::swift_retain(key.key_path as *mut c_void);
791
792 let (meta, wt, size) = super::opaque_result_type(
793 resolve::environment_oret(),
794 &[view.meta, T::metadata(), view.wt],
795 );
796 let mut result = vec![0u8; size];
797 let this = view.value_ptr();
798 core::arch::asm!("blr {f}", f = in(reg) resolve::environment_fn(),
799 in("x0") key.key_path,
800 in("x1") boxed.as_mut_ptr(),
801 in("x2") view.meta,
802 in("x3") view.wt,
803 in("x8") result.as_mut_ptr(),
804 in("x20") this,
805 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
806 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
807 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
808 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
809 );
810 wrap_owned(result, meta, wt)
811 }
812}
813
814pub struct CustomContainerKey<T: KeyValue = i64> {
830 slot: usize,
831 key_path: u64,
832 value: core::marker::PhantomData<fn() -> T>,
833}
834
835impl<T: KeyValue> CustomContainerKey<T> {
836 #[doc(hidden)]
839 pub fn default_for_test(&self) -> T {
840 let (key_meta, key_wt) = {
841 let r = container_registry().lock().expect("container key registry");
842 let e = r[self.slot].as_ref().expect("a registered container key");
843 (e.key_meta as *const c_void, e.key_wt as *const c_void)
844 };
845 unsafe { read_default(key_wt, 1, key_meta) }
847 }
848}
849
850struct ContainerRegistered {
854 key_meta: usize,
855 key_wt: usize,
856 key_path: u64,
857 write_default: Box<dyn Fn(*mut u8) + Send + Sync>,
858}
859
860fn container_registry() -> &'static Mutex<Vec<Option<ContainerRegistered>>> {
861 static R: OnceLock<Mutex<Vec<Option<ContainerRegistered>>>> = OnceLock::new();
862 R.get_or_init(|| Mutex::new((0..keypath::VALUE_SLOTS).map(|_| None).collect()))
863}
864
865fn container_named() -> &'static Mutex<Vec<(String, usize)>> {
866 static N: OnceLock<Mutex<Vec<(String, usize)>>> = OnceLock::new();
867 N.get_or_init(|| Mutex::new(Vec::new()))
868}
869
870crate::thunk::runtime_thunk! {
871 fn container_default_thunk = "rswift_container_default" via RSWIFT_CONTAINER_DEFAULT {
873 prologue: ["mov x1, x20", "mov x0, x8"],
874 branch: "br",
875 epilogue: [],
876 }
877}
878
879unsafe extern "C" fn container_default(out: *mut u8, meta: *const c_void) {
884 let r = container_registry().lock().expect("container key registry");
885 let entry = r
886 .iter()
887 .flatten()
888 .find(|e| e.key_meta == meta as usize)
889 .unwrap_or_else(|| {
890 panic!("no container key registered for {}", crate::diag::type_name(meta))
891 });
892 (entry.write_default)(out);
893}
894
895unsafe extern "C" fn container_get(out: *mut u8, root: *const c_void, index: u64) {
900 let (meta, wt) = {
901 let r = container_registry().lock().expect("container key registry");
902 let e = r[index as usize].as_ref().expect("a registered container key");
903 (e.key_meta as *const c_void, e.key_wt as *const c_void)
904 };
905 unsafe {
906 core::arch::asm!("blr {f}", f = in(reg) resolve::container_values_get(),
907 in("x0") meta, in("x1") meta, in("x2") wt,
908 in("x8") out, in("x20") root,
909 lateout("x3") _, lateout("x4") _, lateout("x5") _, lateout("x6") _,
910 lateout("x7") _,
911 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
912 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
913 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
914 );
915 }
916}
917
918unsafe extern "C" fn container_set(value: *const u8, root: *mut c_void, index: u64) {
923 let (meta, wt) = {
924 let r = container_registry().lock().expect("container key registry");
925 let e = r[index as usize].as_ref().expect("a registered container key");
926 (e.key_meta as *const c_void, e.key_wt as *const c_void)
927 };
928 unsafe {
929 core::arch::asm!("blr {f}", f = in(reg) resolve::container_values_set(),
930 in("x0") value, in("x1") meta, in("x2") meta, in("x3") wt,
931 in("x20") root,
932 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
933 lateout("x8") _,
934 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
935 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
936 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
937 );
938 }
939}
940
941pub fn container_key<T: KeyValue>(
947 name: &str,
948 default: impl IntoKeyValue<T>,
949) -> CustomContainerKey<T> {
950 let default = default.into_key_value();
951 let mut names = container_named().lock().expect("container key names");
952 if let Some(&(_, slot)) = names.iter().find(|(n, _)| n == name) {
953 let key_path = container_registry().lock().expect("container key registry")[slot]
954 .as_ref()
955 .expect("a registered container key")
956 .key_path;
957 return CustomContainerKey { slot, key_path, value: core::marker::PhantomData };
958 }
959
960 let slot = keypath::next_value_slot();
961 names.push((name.to_string(), slot));
962
963 unsafe {
964 let type_name: &'static [u8] = leak_cstr(&format!("RustContainerKey{slot}"));
965 let mangled: &'static [u8] =
966 leak_cstr(&format!("6rswift{}RustContainerKey{slot}V", 16 + digits(slot)));
967 let (descriptor, key_meta) = crate::state::emit_int_carrier(type_name, mangled);
968
969 let protocol = Protocol::from_symbol(c"$s7SwiftUI17ContainerValueKeyMp");
970 assert_eq!(
971 protocol.requirement_count(),
972 2,
973 "ContainerValueKey changed shape — it used to be Value and defaultValue",
974 );
975 let conformance: &'static Conformance = Box::leak(Box::new(synthesize(
976 &protocol,
977 descriptor,
978 &[
979 Witness::Metadata(T::metadata()),
980 Witness::Function(container_default_thunk as *const c_void),
981 ],
982 )));
983 let key_wt = conformance.witness_table();
984
985 let (get, set, get_target, set_target) = keypath::value_thunks(slot);
986 *get_target = container_get as *const c_void;
987 *set_target = container_set as *const c_void;
988 RSWIFT_CONTAINER_DEFAULT = container_default as *const c_void;
989 container_registry().lock().expect("container key registry")[slot] =
990 Some(ContainerRegistered {
991 key_meta: key_meta as usize,
992 key_wt: key_wt as usize,
993 key_path: 0,
994 write_default: Box::new(move |out| default.write(out)),
996 });
997
998 let key_path = keypath::build_writable_computed(
999 keypath::value_slot(slot),
1000 swift_type!(SwiftUI.ContainerValues).as_bytes(),
1001 T::mangled().as_bytes(),
1002 get,
1003 set,
1004 );
1005 swift_runtime_sys::RuntimeRaw::swift_retain(key_path as *mut c_void);
1006 container_registry().lock().expect("container key registry")[slot]
1007 .as_mut()
1008 .expect("just registered")
1009 .key_path = key_path;
1010
1011 CustomContainerKey { slot, key_path, value: core::marker::PhantomData }
1012 }
1013}
1014
1015pub fn container_value<T: KeyValue>(
1021 view: &ViewHandle,
1022 key: &CustomContainerKey<T>,
1023 value: impl IntoKeyValue<T>,
1024) -> ViewHandle {
1025 let value = value.into_key_value();
1026 unsafe {
1027 let _ = key.slot;
1028 let modifier_meta =
1029 crate::abi::generic_metadata1(resolve::container_write_ma(), T::metadata());
1030 assert!(
1031 !modifier_meta.is_null(),
1032 "_ContainerValueWritingModifier<{}> metadata",
1033 crate::diag::type_name(T::metadata()),
1034 );
1035
1036 let offsets = crate::abi::struct_field_offsets(modifier_meta)
1042 .expect("_ContainerValueWritingModifier has reflection metadata");
1043 assert_eq!(offsets.len(), 2, "_ContainerValueWritingModifier changed shape");
1044 let mut modifier = vec![0u8; crate::abi::type_bytes(modifier_meta)];
1045 swift_runtime_sys::RuntimeRaw::swift_retain(key.key_path as *mut c_void);
1047 modifier[offsets[0]..offsets[0] + 8].copy_from_slice(&key.key_path.to_le_bytes());
1048 value.write(modifier.as_mut_ptr().add(offsets[1]));
1051
1052 let meta = crate::abi::generic_metadata2(
1053 resolve::modified_content_ma(),
1054 view.meta,
1055 modifier_meta,
1056 );
1057 assert!(!meta.is_null(), "ModifiedContent metadata");
1058 let wt = crate::abi::get_view_wt(meta);
1059 assert!(!wt.is_null(), "{} !: View", crate::diag::type_name(meta));
1060
1061 let mut result = vec![0u8; crate::abi::type_bytes(meta)];
1062 let this = view.value_ptr();
1063 core::arch::asm!("blr {f}", f = in(reg) resolve::apply_view_modifier_fn(),
1064 in("x0") modifier.as_mut_ptr(),
1065 in("x1") view.meta,
1066 in("x2") modifier_meta,
1067 in("x3") view.wt,
1068 in("x8") result.as_mut_ptr(),
1069 in("x20") this,
1070 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
1071 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
1072 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
1073 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
1074 );
1075 wrap_owned(result, meta, wt)
1076 }
1077}