use crate::abi;
use crate::views::ViewHandle;
use core::ffi::c_void;
const CAST_COPY: u32 = 0;
pub unsafe fn is_type(
value: *const c_void,
source: *const c_void,
target: *const c_void,
) -> bool {
unsafe {
let mut scratch = vec![0u8; abi::type_bytes(target).max(1)];
let ok = swift_runtime_sys::DynamicCast::swift_dynamicCast(
scratch.as_mut_ptr() as *mut c_void,
value as *mut c_void,
source,
target,
CAST_COPY,
);
if ok {
let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(target);
if vwt.size > 0 {
(vwt.destroy)(scratch.as_mut_ptr() as *mut c_void, target);
}
}
ok
}
}
pub fn view_is(view: &ViewHandle, mangled: &str) -> bool {
unsafe {
let target = abi::resolve_type_by_mangled_name(mangled.as_bytes());
if target.is_null() {
return false;
}
is_type(view.value_ptr(), views_meta(view), target)
}
}
fn views_meta(view: &ViewHandle) -> *const c_void {
crate::views::meta_of(view)
}
pub unsafe fn cast_class(object: *const c_void, target: *const c_void) -> Option<*const c_void> {
let out =
unsafe { swift_runtime_sys::DynamicCast::swift_dynamicCastClass(object, target) };
(!out.is_null()).then_some(out)
}
pub unsafe fn cast_metatype(
source: *const c_void,
target: *const c_void,
) -> Option<*const c_void> {
let out = unsafe {
swift_runtime_sys::DynamicCast::swift_dynamicCastMetatype(source, target)
};
(!out.is_null()).then_some(out)
}
pub struct SwiftError {
boxed: *mut c_void,
payload_meta: *const c_void,
}
impl SwiftError {
pub unsafe fn new(
value: *const c_void,
meta: *const c_void,
wt: *const c_void,
) -> Self {
unsafe {
let pair = swift_runtime_sys::ErrorHandling::swift_allocError(
meta,
wt,
value as *mut c_void,
false,
);
assert!(!pair.object.is_null(), "swift_allocError returned nothing");
Self { boxed: pair.object, payload_meta: meta }
}
}
pub fn as_ptr(&self) -> *mut c_void {
self.boxed
}
pub fn payload_type_name(&self) -> String {
unsafe {
let mut scratch: *mut c_void = core::ptr::null_mut();
let mut out = swift_runtime_sys::ErrorHandling::ErrorValueResult {
value: core::ptr::null(),
error_type: core::ptr::null(),
error_conformance: core::ptr::null(),
};
swift_runtime_sys::ErrorHandling::swift_getErrorValue(
self.boxed,
&mut scratch,
&mut out,
);
assert!(!out.error_type.is_null(), "the error box has no type");
crate::diag::type_name(out.error_type)
}
}
pub unsafe fn payload(&self) -> &[u8] {
unsafe {
let mut scratch: *mut c_void = core::ptr::null_mut();
let mut out = swift_runtime_sys::ErrorHandling::ErrorValueResult {
value: core::ptr::null(),
error_type: core::ptr::null(),
error_conformance: core::ptr::null(),
};
swift_runtime_sys::ErrorHandling::swift_getErrorValue(
self.boxed,
&mut scratch,
&mut out,
);
core::slice::from_raw_parts(
out.value as *const u8,
abi::type_size(self.payload_meta),
)
}
}
}
impl Clone for SwiftError {
fn clone(&self) -> Self {
unsafe {
swift_runtime_sys::ErrorHandling::swift_errorRetain(self.boxed);
}
Self { boxed: self.boxed, payload_meta: self.payload_meta }
}
}
impl Drop for SwiftError {
fn drop(&mut self) {
unsafe { swift_runtime_sys::ErrorHandling::swift_errorRelease(self.boxed) };
}
}
pub fn error_code(code: i64) -> SwiftError {
unsafe {
let (meta, wt) = *error_carrier();
let mut value = code;
SwiftError::new(
&mut value as *mut i64 as *const c_void,
meta as *const c_void,
wt as *const c_void,
)
}
}
fn error_carrier() -> &'static (usize, usize) {
static C: std::sync::OnceLock<(usize, usize)> = std::sync::OnceLock::new();
C.get_or_init(|| unsafe {
let (descriptor, meta) =
crate::state::emit_int_carrier(b"RustError\0", b"6rswift9RustErrorV\0");
let protocol = crate::conformance::Protocol::from_symbol(c"$ss5ErrorMp");
let witnesses: Vec<crate::conformance::Witness> = (0..protocol.requirement_count())
.map(|_| crate::conformance::Witness::Default)
.collect();
let conformance = Box::leak(Box::new(crate::conformance::synthesize(
&protocol,
descriptor,
&witnesses,
)));
(meta as usize, conformance.witness_table() as usize)
})
}
pub struct Task {
task: *mut c_void,
state: std::sync::Arc<crate::asyncfn::TaskState>,
}
unsafe impl Send for Task {}
unsafe impl Sync for Task {}
impl Task {
pub fn is_cancelled(&self) -> bool {
unsafe { task_is_cancelled(self.task) }
}
pub fn cancel(&self) {
unsafe { task_cancel(self.task) };
}
pub fn priority(&self) -> u32 {
unsafe { task_base_priority(self.task) }
}
pub fn is_finished(&self) -> bool {
self.state.is_finished()
}
pub fn wait(&self) {
self.state.wait(None);
}
pub fn wait_timeout(&self, limit: std::time::Duration) -> bool {
self.state.wait(Some(limit))
}
}
impl Drop for Task {
fn drop(&mut self) {
unsafe { swift_runtime_sys::RuntimeRaw::swift_release(self.task) };
}
}
pub struct CurrentTask {
task: *mut c_void,
}
impl CurrentTask {
pub fn is_cancelled(&self) -> bool {
unsafe { task_is_cancelled(self.task) }
}
pub fn priority(&self) -> u32 {
unsafe { task_base_priority(self.task) }
}
}
pub fn detached(body: impl FnOnce() + Send + 'static) -> Task {
spawn(None, Box::new(body))
}
pub fn detached_with_priority(
priority: crate::views::TaskPriority,
body: impl FnOnce() + Send + 'static,
) -> Task {
spawn(Some(priority), Box::new(body))
}
const ENQUEUE_JOB: usize = 1 << 12;
fn spawn(
priority: Option<crate::views::TaskPriority>,
body: Box<dyn FnOnce() + Send>,
) -> Task {
let state = std::sync::Arc::new(crate::asyncfn::TaskState::new());
unsafe {
let (record, context) = crate::asyncfn::task_entry_point(body, &state);
let unit = crate::abi::resolve_type_by_mangled_name(b"yt");
assert!(!unit.is_null(), "() metadata");
let raw = priority.map_or(0usize, |p| {
let meta = crate::abi::metadata0(crate::resolve::task_priority_ma());
assert!(!meta.is_null(), "TaskPriority metadata");
let bytes = crate::views::resilient_static(meta, p.getter());
usize::from(bytes[0])
});
let created = task_create()(
ENQUEUE_JOB | raw,
core::ptr::null_mut(),
unit,
record,
context,
);
assert!(!created.task.is_null(), "swift_task_create returned nothing");
Task { task: created.task, state }
}
}
type TaskCreate = unsafe extern "C" fn(
usize,
*mut c_void,
*const c_void,
*const c_void,
*mut c_void,
) -> swift_runtime_sys::ConcurrencyRuntime::AsyncTaskAndContext;
unsafe fn task_create() -> TaskCreate {
unsafe { core::mem::transmute(crate::resolve::require(c"swift_task_create")) }
}
unsafe fn task_of<R>(name: &'static core::ffi::CStr) -> unsafe extern "C" fn(*mut c_void) -> R {
unsafe { core::mem::transmute(crate::resolve::require(name)) }
}
unsafe fn task_get_current() -> *mut c_void {
let f: unsafe extern "C" fn() -> *mut c_void =
unsafe { core::mem::transmute(crate::resolve::require(c"swift_task_getCurrent")) };
unsafe { f() }
}
unsafe fn task_is_cancelled(task: *mut c_void) -> bool {
unsafe { task_of::<bool>(c"swift_task_isCancelled")(task) }
}
unsafe fn task_cancel(task: *mut c_void) {
unsafe { task_of::<()>(c"swift_task_cancel")(task) }
}
unsafe fn task_base_priority(task: *mut c_void) -> u32 {
unsafe { task_of::<u32>(c"swift_task_basePriority")(task) }
}
pub fn current_task() -> Option<CurrentTask> {
let task = unsafe { task_get_current() };
(!task.is_null()).then_some(CurrentTask { task })
}