use super::{wrap_owned, ViewHandle};
use crate::conformance::{synthesize, Conformance, Protocol, Witness};
use crate::keypath;
use crate::mangle::{self, swift_type};
use crate::resolve;
use core::ffi::c_void;
use std::sync::{Mutex, OnceLock};
pub trait KeyValue: Clone + Send + Sync + 'static {
fn mangled() -> &'static str;
fn metadata() -> *const c_void;
unsafe fn write(&self, out: *mut u8);
unsafe fn read(from: *const u8) -> Self;
}
pub trait IntoKeyValue<T: KeyValue> {
fn into_key_value(self) -> T;
}
impl<T: KeyValue> IntoKeyValue<T> for T {
fn into_key_value(self) -> T {
self
}
}
impl IntoKeyValue<String> for &str {
fn into_key_value(self) -> String {
self.to_string()
}
}
impl KeyValue for i64 {
fn mangled() -> &'static str {
crate::mangle::INT
}
fn metadata() -> *const c_void {
resolve::int_meta()
}
unsafe fn write(&self, out: *mut u8) {
unsafe { *(out as *mut i64) = *self };
}
unsafe fn read(from: *const u8) -> Self {
unsafe { *(from as *const i64) }
}
}
impl KeyValue for f64 {
fn mangled() -> &'static str {
crate::mangle::DOUBLE
}
fn metadata() -> *const c_void {
resolve::double_meta()
}
unsafe fn write(&self, out: *mut u8) {
unsafe { *(out as *mut f64) = *self };
}
unsafe fn read(from: *const u8) -> Self {
unsafe { *(from as *const f64) }
}
}
impl KeyValue for bool {
fn mangled() -> &'static str {
crate::mangle::BOOL
}
fn metadata() -> *const c_void {
resolve::bool_meta()
}
unsafe fn write(&self, out: *mut u8) {
unsafe { *out = u8::from(*self) };
}
unsafe fn read(from: *const u8) -> Self {
unsafe { *from & 1 != 0 }
}
}
impl KeyValue for String {
fn mangled() -> &'static str {
crate::mangle::STRING
}
fn metadata() -> *const c_void {
resolve::string_meta()
}
unsafe fn write(&self, out: *mut u8) {
let bytes = unsafe { crate::abi::swift_string(self) };
unsafe { core::ptr::copy_nonoverlapping(bytes.as_ptr(), out, 16) };
}
unsafe fn read(from: *const u8) -> Self {
let mut bytes = [0u8; 16];
unsafe { core::ptr::copy_nonoverlapping(from, bytes.as_mut_ptr(), 16) };
unsafe { crate::abi::read_swift_string(bytes) }
}
}
unsafe fn read_default<T: KeyValue>(
table: *const c_void,
slot: usize,
key_meta: *const c_void,
) -> T {
unsafe {
let witness = *(table as *const *const c_void).add(slot + 1);
let mut out = vec![0u8; crate::abi::type_bytes(T::metadata())];
core::arch::asm!("blr {f}", f = in(reg) witness,
in("x8") out.as_mut_ptr(),
in("x20") key_meta,
lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
);
let value = T::read(out.as_ptr());
crate::abi::type_destroy(T::metadata(), out.as_mut_ptr());
value
}
}
pub struct FocusKey<T: KeyValue = i64> {
slot: usize,
key_path: u64,
value: core::marker::PhantomData<fn() -> T>,
}
impl<T: KeyValue> FocusKey<T> {
#[doc(hidden)]
pub fn key_path_for_test(&self) -> u64 {
self.key_path
}
#[doc(hidden)]
pub fn parts_for_test(&self) -> (usize, usize) {
let r = registry().lock().expect("focus key registry");
let e = r[self.slot].as_ref().expect("a registered focus key");
(e.key_meta, e.key_wt)
}
}
struct Registered {
key_meta: usize,
key_wt: usize,
key_path: u64,
}
fn registry() -> &'static Mutex<Vec<Option<Registered>>> {
static R: OnceLock<Mutex<Vec<Option<Registered>>>> = OnceLock::new();
R.get_or_init(|| Mutex::new((0..keypath::VALUE_SLOTS).map(|_| None).collect()))
}
fn named() -> &'static Mutex<Vec<(String, usize)>> {
static N: OnceLock<Mutex<Vec<(String, usize)>>> = OnceLock::new();
N.get_or_init(|| Mutex::new(Vec::new()))
}
pub fn focus_key<T: KeyValue>(name: &str) -> FocusKey<T> {
let mut names = named().lock().expect("focus key names");
if let Some(&(_, slot)) = names.iter().find(|(n, _)| n == name) {
let key_path = registry().lock().expect("focus key registry")[slot]
.as_ref()
.expect("a registered focus key")
.key_path;
return FocusKey { slot, key_path, value: core::marker::PhantomData };
}
let slot = keypath::next_value_slot();
names.push((name.to_string(), slot));
unsafe {
let type_name: &'static [u8] = leak_cstr(&format!("RustFocusKey{slot}"));
let mangled: &'static [u8] =
leak_cstr(&format!("6rswift{}RustFocusKey{slot}V", 12 + digits(slot)));
let (descriptor, key_meta) = crate::state::emit_int_carrier(type_name, mangled);
let protocol = Protocol::from_symbol(c"$s7SwiftUI15FocusedValueKeyMp");
assert_eq!(
protocol.requirement_count(),
1,
"FocusedValueKey changed shape — it used to be one associated type",
);
let conformance: &'static Conformance = Box::leak(Box::new(synthesize(
&protocol,
descriptor,
&[Witness::Metadata(T::metadata())],
)));
let key_wt = conformance.witness_table();
let (get, set, get_target, set_target) = keypath::value_thunks(slot);
*get_target = focus_get as *const c_void;
*set_target = focus_set as *const c_void;
registry().lock().expect("focus key registry")[slot] = Some(Registered {
key_meta: key_meta as usize,
key_wt: key_wt as usize,
key_path: 0,
});
let key_path = keypath::build_writable_computed(
keypath::value_slot(slot),
swift_type!(SwiftUI.FocusedValues).as_bytes(),
mangle::optional(T::mangled()).as_bytes(),
get,
set,
);
swift_runtime_sys::RuntimeRaw::swift_retain(key_path as *mut c_void);
registry().lock().expect("focus key registry")[slot]
.as_mut()
.expect("just registered")
.key_path = key_path;
FocusKey { slot, key_path, value: core::marker::PhantomData }
}
}
static GETS: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
static SETS: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
#[doc(hidden)]
pub fn focus_accessor_counts() -> (usize, usize) {
use std::sync::atomic::Ordering::Relaxed;
(GETS.load(Relaxed), SETS.load(Relaxed))
}
fn digits(n: usize) -> usize {
if n < 10 {
1
} else if n < 100 {
2
} else {
3
}
}
fn leak_cstr(s: &str) -> &'static [u8] {
let mut bytes = s.as_bytes().to_vec();
bytes.push(0);
Box::leak(bytes.into_boxed_slice())
}
unsafe extern "C" fn focus_get(out: *mut u8, root: *const c_void, index: u64) {
GETS.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let (meta, wt) = {
let r = registry().lock().expect("focus key registry");
let e = r[index as usize].as_ref().expect("a registered focus key");
(e.key_meta as *const c_void, e.key_wt as *const c_void)
};
unsafe {
core::arch::asm!("blr {f}", f = in(reg) resolve::focused_values_get(),
in("x0") meta,
in("x1") meta,
in("x2") wt,
in("x8") out,
in("x20") root,
lateout("x3") _, lateout("x4") _, lateout("x5") _, lateout("x6") _,
lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
);
}
}
unsafe extern "C" fn focus_set(value: *const u8, root: *mut c_void, index: u64) {
SETS.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let (meta, wt) = {
let r = registry().lock().expect("focus key registry");
let e = r[index as usize].as_ref().expect("a registered focus key");
(e.key_meta as *const c_void, e.key_wt as *const c_void)
};
unsafe {
core::arch::asm!("blr {f}", f = in(reg) resolve::focused_values_set(),
in("x0") value,
in("x1") meta,
in("x2") meta,
in("x3") wt,
in("x20") root,
lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
lateout("x8") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
);
}
}
pub fn focused_scene_value<T: KeyValue>(
view: &ViewHandle,
key: &FocusKey<T>,
value: impl IntoKeyValue<T>,
) -> ViewHandle {
unsafe {
publish(
view,
key,
value.into_key_value(),
resolve::focused_scene_value_fn(),
resolve::focused_scene_value_oret(),
)
}
}
pub fn focused_value_keyed<T: KeyValue>(
view: &ViewHandle,
key: &FocusKey<T>,
value: impl IntoKeyValue<T>,
) -> ViewHandle {
unsafe {
publish(
view,
key,
value.into_key_value(),
resolve::focused_value_kp_fn(),
resolve::focused_value_kp_oret(),
)
}
}
unsafe fn publish<T: KeyValue>(
view: &ViewHandle,
key: &FocusKey<T>,
value: T,
f: *const c_void,
oret: *const c_void,
) -> ViewHandle {
unsafe {
let mut boxed = vec![0u8; crate::abi::type_bytes(T::metadata())];
value.write(boxed.as_mut_ptr());
swift_runtime_sys::RuntimeRaw::swift_retain(key.key_path as *mut c_void);
let (meta, wt, size) =
super::opaque_result_type(oret, &[view.meta, T::metadata(), view.wt]);
let mut result = vec![0u8; size];
let this = view.value_ptr();
core::arch::asm!("blr {f}", f = in(reg) f,
in("x0") key.key_path,
in("x1") boxed.as_mut_ptr(),
in("x2") view.meta,
in("x3") view.wt,
in("x8") result.as_mut_ptr(),
in("x20") this,
lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub struct CustomEnvKey<T: KeyValue = i64> {
slot: usize,
key_path: u64,
value: core::marker::PhantomData<fn() -> T>,
}
impl<T: KeyValue> CustomEnvKey<T> {
#[doc(hidden)]
pub fn default_for_test(&self) -> T {
let (key_meta, key_wt) = {
let r = env_registry().lock().expect("environment key registry");
let e = r[self.slot].as_ref().expect("a registered environment key");
(e.key_meta as *const c_void, e.key_wt as *const c_void)
};
unsafe { read_default(key_wt, 1, key_meta) }
}
#[doc(hidden)]
pub fn key_path_for_test(&self) -> u64 {
self.key_path
}
}
struct EnvRegistered {
key_meta: usize,
key_wt: usize,
key_path: u64,
write_default: Box<dyn Fn(*mut u8) + Send + Sync>,
}
fn env_registry() -> &'static Mutex<Vec<Option<EnvRegistered>>> {
static R: OnceLock<Mutex<Vec<Option<EnvRegistered>>>> = OnceLock::new();
R.get_or_init(|| Mutex::new((0..keypath::VALUE_SLOTS).map(|_| None).collect()))
}
fn env_named() -> &'static Mutex<Vec<(String, usize)>> {
static N: OnceLock<Mutex<Vec<(String, usize)>>> = OnceLock::new();
N.get_or_init(|| Mutex::new(Vec::new()))
}
fn env_slot_for(meta: *const c_void) -> usize {
let r = env_registry().lock().expect("environment key registry");
r.iter()
.position(|e| e.as_ref().is_some_and(|e| e.key_meta == meta as usize))
.unwrap_or_else(|| {
panic!("no environment key registered for {}", crate::diag::type_name(meta))
})
}
crate::thunk::runtime_thunk! {
fn env_default_thunk = "rswift_env_default" via RSWIFT_ENV_DEFAULT {
prologue: ["mov x1, x20", "mov x0, x8"],
branch: "br",
epilogue: [],
}
}
unsafe extern "C" fn env_default(out: *mut u8, meta: *const c_void) {
let slot = env_slot_for(meta);
let r = env_registry().lock().expect("environment key registry");
(r[slot].as_ref().expect("a registered environment key").write_default)(out);
}
unsafe extern "C" fn env_get(out: *mut u8, root: *const c_void, index: u64) {
let (meta, wt) = {
let r = env_registry().lock().expect("environment key registry");
let e = r[index as usize].as_ref().expect("a registered environment key");
(e.key_meta as *const c_void, e.key_wt as *const c_void)
};
unsafe {
core::arch::asm!("blr {f}", f = in(reg) resolve::environment_values_get(),
in("x0") meta,
in("x1") meta,
in("x2") wt,
in("x8") out,
in("x20") root,
lateout("x3") _, lateout("x4") _, lateout("x5") _, lateout("x6") _,
lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
);
}
}
unsafe extern "C" fn env_set(value: *const u8, root: *mut c_void, index: u64) {
let (meta, wt) = {
let r = env_registry().lock().expect("environment key registry");
let e = r[index as usize].as_ref().expect("a registered environment key");
(e.key_meta as *const c_void, e.key_wt as *const c_void)
};
unsafe {
core::arch::asm!("blr {f}", f = in(reg) resolve::environment_values_set(),
in("x0") value,
in("x1") meta,
in("x2") meta,
in("x3") wt,
in("x20") root,
lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
lateout("x8") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
);
}
}
pub fn env_key<T: KeyValue>(name: &str, default: impl IntoKeyValue<T>) -> CustomEnvKey<T> {
let default = default.into_key_value();
let mut names = env_named().lock().expect("environment key names");
if let Some(&(_, slot)) = names.iter().find(|(n, _)| n == name) {
let key_path = env_registry().lock().expect("environment key registry")[slot]
.as_ref()
.expect("a registered environment key")
.key_path;
return CustomEnvKey { slot, key_path, value: core::marker::PhantomData };
}
let slot = keypath::next_value_slot();
names.push((name.to_string(), slot));
unsafe {
let type_name: &'static [u8] = leak_cstr(&format!("RustEnvKey{slot}"));
let mangled: &'static [u8] =
leak_cstr(&format!("6rswift{}RustEnvKey{slot}V", 10 + digits(slot)));
let (descriptor, key_meta) = crate::state::emit_int_carrier(type_name, mangled);
let protocol = Protocol::from_symbol(c"$s7SwiftUI14EnvironmentKeyMp");
assert_eq!(
protocol.requirement_count(),
3,
"EnvironmentKey changed shape — it used to be Value, defaultValue and \
one defaulted requirement",
);
let conformance: &'static Conformance = Box::leak(Box::new(synthesize(
&protocol,
descriptor,
&[
Witness::Metadata(T::metadata()),
Witness::Function(env_default_thunk as *const c_void),
Witness::Default,
],
)));
let key_wt = conformance.witness_table();
let (get, set, get_target, set_target) = keypath::value_thunks(slot);
*get_target = env_get as *const c_void;
*set_target = env_set as *const c_void;
RSWIFT_ENV_DEFAULT = env_default as *const c_void;
env_registry().lock().expect("environment key registry")[slot] = Some(EnvRegistered {
key_meta: key_meta as usize,
key_wt: key_wt as usize,
key_path: 0,
write_default: Box::new(move |out| default.write(out)),
});
let key_path = keypath::build_writable_computed(
keypath::value_slot(slot),
swift_type!(SwiftUI.EnvironmentValues).as_bytes(),
T::mangled().as_bytes(),
get,
set,
);
swift_runtime_sys::RuntimeRaw::swift_retain(key_path as *mut c_void);
env_registry().lock().expect("environment key registry")[slot]
.as_mut()
.expect("just registered")
.key_path = key_path;
CustomEnvKey { slot, key_path, value: core::marker::PhantomData }
}
}
pub fn environment_value<T: KeyValue>(
view: &ViewHandle,
key: &CustomEnvKey<T>,
value: impl IntoKeyValue<T>,
) -> ViewHandle {
let value = value.into_key_value();
unsafe {
let _ = key.slot;
let mut boxed = vec![0u8; crate::abi::type_bytes(T::metadata()).max(1)];
value.write(boxed.as_mut_ptr());
swift_runtime_sys::RuntimeRaw::swift_retain(key.key_path as *mut c_void);
let (meta, wt, size) = super::opaque_result_type(
resolve::environment_oret(),
&[view.meta, T::metadata(), view.wt],
);
let mut result = vec![0u8; size];
let this = view.value_ptr();
core::arch::asm!("blr {f}", f = in(reg) resolve::environment_fn(),
in("x0") key.key_path,
in("x1") boxed.as_mut_ptr(),
in("x2") view.meta,
in("x3") view.wt,
in("x8") result.as_mut_ptr(),
in("x20") this,
lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}
pub struct CustomContainerKey<T: KeyValue = i64> {
slot: usize,
key_path: u64,
value: core::marker::PhantomData<fn() -> T>,
}
impl<T: KeyValue> CustomContainerKey<T> {
#[doc(hidden)]
pub fn default_for_test(&self) -> T {
let (key_meta, key_wt) = {
let r = container_registry().lock().expect("container key registry");
let e = r[self.slot].as_ref().expect("a registered container key");
(e.key_meta as *const c_void, e.key_wt as *const c_void)
};
unsafe { read_default(key_wt, 1, key_meta) }
}
}
struct ContainerRegistered {
key_meta: usize,
key_wt: usize,
key_path: u64,
write_default: Box<dyn Fn(*mut u8) + Send + Sync>,
}
fn container_registry() -> &'static Mutex<Vec<Option<ContainerRegistered>>> {
static R: OnceLock<Mutex<Vec<Option<ContainerRegistered>>>> = OnceLock::new();
R.get_or_init(|| Mutex::new((0..keypath::VALUE_SLOTS).map(|_| None).collect()))
}
fn container_named() -> &'static Mutex<Vec<(String, usize)>> {
static N: OnceLock<Mutex<Vec<(String, usize)>>> = OnceLock::new();
N.get_or_init(|| Mutex::new(Vec::new()))
}
crate::thunk::runtime_thunk! {
fn container_default_thunk = "rswift_container_default" via RSWIFT_CONTAINER_DEFAULT {
prologue: ["mov x1, x20", "mov x0, x8"],
branch: "br",
epilogue: [],
}
}
unsafe extern "C" fn container_default(out: *mut u8, meta: *const c_void) {
let r = container_registry().lock().expect("container key registry");
let entry = r
.iter()
.flatten()
.find(|e| e.key_meta == meta as usize)
.unwrap_or_else(|| {
panic!("no container key registered for {}", crate::diag::type_name(meta))
});
(entry.write_default)(out);
}
unsafe extern "C" fn container_get(out: *mut u8, root: *const c_void, index: u64) {
let (meta, wt) = {
let r = container_registry().lock().expect("container key registry");
let e = r[index as usize].as_ref().expect("a registered container key");
(e.key_meta as *const c_void, e.key_wt as *const c_void)
};
unsafe {
core::arch::asm!("blr {f}", f = in(reg) resolve::container_values_get(),
in("x0") meta, in("x1") meta, in("x2") wt,
in("x8") out, in("x20") root,
lateout("x3") _, lateout("x4") _, lateout("x5") _, lateout("x6") _,
lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
);
}
}
unsafe extern "C" fn container_set(value: *const u8, root: *mut c_void, index: u64) {
let (meta, wt) = {
let r = container_registry().lock().expect("container key registry");
let e = r[index as usize].as_ref().expect("a registered container key");
(e.key_meta as *const c_void, e.key_wt as *const c_void)
};
unsafe {
core::arch::asm!("blr {f}", f = in(reg) resolve::container_values_set(),
in("x0") value, in("x1") meta, in("x2") meta, in("x3") wt,
in("x20") root,
lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
lateout("x8") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
);
}
}
pub fn container_key<T: KeyValue>(
name: &str,
default: impl IntoKeyValue<T>,
) -> CustomContainerKey<T> {
let default = default.into_key_value();
let mut names = container_named().lock().expect("container key names");
if let Some(&(_, slot)) = names.iter().find(|(n, _)| n == name) {
let key_path = container_registry().lock().expect("container key registry")[slot]
.as_ref()
.expect("a registered container key")
.key_path;
return CustomContainerKey { slot, key_path, value: core::marker::PhantomData };
}
let slot = keypath::next_value_slot();
names.push((name.to_string(), slot));
unsafe {
let type_name: &'static [u8] = leak_cstr(&format!("RustContainerKey{slot}"));
let mangled: &'static [u8] =
leak_cstr(&format!("6rswift{}RustContainerKey{slot}V", 16 + digits(slot)));
let (descriptor, key_meta) = crate::state::emit_int_carrier(type_name, mangled);
let protocol = Protocol::from_symbol(c"$s7SwiftUI17ContainerValueKeyMp");
assert_eq!(
protocol.requirement_count(),
2,
"ContainerValueKey changed shape — it used to be Value and defaultValue",
);
let conformance: &'static Conformance = Box::leak(Box::new(synthesize(
&protocol,
descriptor,
&[
Witness::Metadata(T::metadata()),
Witness::Function(container_default_thunk as *const c_void),
],
)));
let key_wt = conformance.witness_table();
let (get, set, get_target, set_target) = keypath::value_thunks(slot);
*get_target = container_get as *const c_void;
*set_target = container_set as *const c_void;
RSWIFT_CONTAINER_DEFAULT = container_default as *const c_void;
container_registry().lock().expect("container key registry")[slot] =
Some(ContainerRegistered {
key_meta: key_meta as usize,
key_wt: key_wt as usize,
key_path: 0,
write_default: Box::new(move |out| default.write(out)),
});
let key_path = keypath::build_writable_computed(
keypath::value_slot(slot),
swift_type!(SwiftUI.ContainerValues).as_bytes(),
T::mangled().as_bytes(),
get,
set,
);
swift_runtime_sys::RuntimeRaw::swift_retain(key_path as *mut c_void);
container_registry().lock().expect("container key registry")[slot]
.as_mut()
.expect("just registered")
.key_path = key_path;
CustomContainerKey { slot, key_path, value: core::marker::PhantomData }
}
}
pub fn container_value<T: KeyValue>(
view: &ViewHandle,
key: &CustomContainerKey<T>,
value: impl IntoKeyValue<T>,
) -> ViewHandle {
let value = value.into_key_value();
unsafe {
let _ = key.slot;
let modifier_meta =
crate::abi::generic_metadata1(resolve::container_write_ma(), T::metadata());
assert!(
!modifier_meta.is_null(),
"_ContainerValueWritingModifier<{}> metadata",
crate::diag::type_name(T::metadata()),
);
let offsets = crate::abi::struct_field_offsets(modifier_meta)
.expect("_ContainerValueWritingModifier has reflection metadata");
assert_eq!(offsets.len(), 2, "_ContainerValueWritingModifier changed shape");
let mut modifier = vec![0u8; crate::abi::type_bytes(modifier_meta)];
swift_runtime_sys::RuntimeRaw::swift_retain(key.key_path as *mut c_void);
modifier[offsets[0]..offsets[0] + 8].copy_from_slice(&key.key_path.to_le_bytes());
value.write(modifier.as_mut_ptr().add(offsets[1]));
let meta = crate::abi::generic_metadata2(
resolve::modified_content_ma(),
view.meta,
modifier_meta,
);
assert!(!meta.is_null(), "ModifiedContent metadata");
let wt = crate::abi::get_view_wt(meta);
assert!(!wt.is_null(), "{} !: View", crate::diag::type_name(meta));
let mut result = vec![0u8; crate::abi::type_bytes(meta)];
let this = view.value_ptr();
core::arch::asm!("blr {f}", f = in(reg) resolve::apply_view_modifier_fn(),
in("x0") modifier.as_mut_ptr(),
in("x1") view.meta,
in("x2") modifier_meta,
in("x3") view.wt,
in("x8") result.as_mut_ptr(),
in("x20") this,
lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
);
wrap_owned(result, meta, wt)
}
}