blob: 0458ae2fe3bdddc05b42a2fc790d2ae8f1f3d7c0 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
use libc::c_char;
use std::{ffi::c_void, net::SocketAddr};
use super::get_string;
unsafe extern "C" {
/// Return the latest available endpoint, or a default one if none are cached
///
/// # SAFETY
/// `rawAddressCacheProvider` **must** be provided by a call to `init_swift_address_cache_wrapper`
/// It is okay to persist it, and use it accross multiple threads.
pub fn swift_get_cached_endpoint(
rawAddressCacheProvider: *const c_void,
) -> LateStringDeallocator;
}
#[derive(Debug)]
#[repr(C)]
pub struct SwiftAddressCacheWrapper(SwiftAddressCacheProviderContext);
impl SwiftAddressCacheWrapper {
pub fn new(context: SwiftAddressCacheProviderContext) -> SwiftAddressCacheWrapper {
SwiftAddressCacheWrapper(context)
}
pub fn get_addrs(&self) -> SocketAddr {
self.context_ref().get_addrs()
}
fn context_ref(&self) -> &SwiftAddressCacheProviderContext {
&self.0
}
}
// SAFETY: The `address_cache` inside the `SwiftAddressCacheProviderContext`'s context is guaranteed to be thread safe
unsafe impl Sync for SwiftAddressCacheProviderContext {}
// SAFETY: The `address_cache` inside the `SwiftAddressCacheProviderContext`'s context is guaranteed to be Sendable
unsafe impl Send for SwiftAddressCacheProviderContext {}
#[derive(Debug)]
#[repr(C)]
pub struct SwiftAddressCacheProviderContext {
address_cache: *const c_void,
}
/// A struct used to deallocate a pointer to a C String later than when the pointer's control is relinquished from Swift.
/// Use the `deallocate_ptr` function on `ptr` to call the custom deallocator provided by Swift.
#[repr(C)]
pub struct LateStringDeallocator {
ptr: *const c_char,
deallocate_ptr: unsafe extern "C" fn(*const c_char),
}
impl SwiftAddressCacheProviderContext {
pub fn get_addrs(&self) -> SocketAddr {
// SAFETY: See notice for `swift_get_cached_endpoint`
let deallocator = unsafe { swift_get_cached_endpoint(self.address_cache) };
// SAFETY: The pointer contained in the late deallocator returned by `swift_get_cached_endpoint`
// is guaranteed to point to a valid UTF-8 String
// It is also guaranteed to be a valid representation of either an IPv4 or IPv6 address
let cached_address = unsafe { get_string(deallocator.ptr) }
.parse()
.expect("Invalid socket address in cache");
// SAFETY: The pointer in `deallocator.ptr` must not be used after `deallocate_ptr` has been called.
// `deallocate_ptr` must be called only once
unsafe { (deallocator.deallocate_ptr)(deallocator.ptr) };
cached_address
}
}
/// Called by the Swift side in order to provide an object to rust that provides API addresses in a UTF-8 string form
///
/// # SAFETY
/// `address_cache` **must be** pointing to a valid instance of a `DefaultAddressCacheProvider`
/// That instance's lifetime has to be equivalent to a `'static` lifetime in Rust
/// This function does not take ownership of `address_cache`
#[unsafe(no_mangle)]
pub unsafe extern "C" fn init_swift_address_cache_wrapper(
address_cache: *const c_void,
) -> SwiftAddressCacheWrapper {
let context = SwiftAddressCacheProviderContext { address_cache };
SwiftAddressCacheWrapper::new(context)
}
|