use safer_ffi::{
derive_ReprC,
dyn_traits::VirtualPtr,
layout::{CLayoutOf, ReprC, __HasNiche__},
option::TaggedOption,
};
use crate::peer_pubkey::PeerPubkey;
pub type Callback<T> = safer_ffi::closure::BoxDynFnMut1<(), T>;
pub type Continuation<'a, T> = safer_ffi::closure::BoxDynFnMut1<(), T>;
pub type Payload = safer_ffi::bytes::Bytes<'static>;
#[derive_ReprC]
#[repr(C)]
pub struct Bus {
pub inner: VirtualPtr<dyn IBus + Send + Sync>,
}
#[derive_ReprC(dyn, Clone)]
pub trait IBus {
extern "C" fn add_acceptor(
&self,
topic: safer_ffi::bytes::Bytes<'static>,
on_accept: Callback<Stream>,
) -> Option<AcceptorId>;
extern "C" fn delete_acceptor(&self, id: Option<AcceptorId>);
extern "C" fn connect(
&self,
with: StreamInfo<'_>,
then: Continuation<'static, ConnectionResult>,
);
extern "C" fn send_single_message(
&self,
to: PeerPubkey,
data: Payload,
reliability: ReliabilityMode,
) -> SendHandle;
extern "C" fn set_recv_single_message_callback(
&self,
callback: TaggedOption<Callback<SingleMessage>>,
) -> TaggedOption<Callback<SingleMessage>>;
}
#[repr(transparent)]
pub struct AcceptorId(pub core::num::NonZeroU32);
unsafe impl ReprC for AcceptorId {
type CLayout = u32;
fn is_valid(it: &'_ Self::CLayout) -> bool {
*it != 0
}
}
unsafe impl __HasNiche__ for AcceptorId {
fn is_niche(it: &'_ <Self as ReprC>::CLayout) -> bool {
*it == 0
}
}
#[test]
fn acceptor_id_layout() {
assert!(AcceptorId::is_niche(&0));
assert!(!AcceptorId::is_valid(&0));
assert!(!AcceptorId::is_niche(&1));
assert!(AcceptorId::is_valid(&1));
assert!(!AcceptorId::is_niche(&u32::MAX));
assert!(AcceptorId::is_valid(&u32::MAX));
}
#[derive_ReprC]
#[repr(u8)]
pub enum ReliabilityMode {
Unreliable,
UnreliableSequenced,
Reliable,
}
#[derive_ReprC]
#[repr(C)]
pub struct SingleMessage {
pub source: PeerPubkey,
pub payload: Payload,
}
#[derive_ReprC]
#[repr(C)]
#[must_use = "Dropping a stream closes the connection."]
pub struct Stream {
pub inner: VirtualPtr<dyn IStream + Send + Sync>,
}
#[derive_ReprC(dyn)]
pub trait IStream {
extern "C" fn info(&self) -> StreamInfo<'_>;
extern "C" fn send(&self, payload: Payload) -> SendHandle;
extern "C" fn set_recv_callback(
&self,
on_recv: TaggedOption<Callback<Payload>>,
) -> TaggedOption<Callback<Payload>>;
extern "C" fn is_closed(&self) -> TaggedOption<StreamClosedBy>;
extern "C" fn add_on_close(&self, continuation: Continuation<'static, StreamClosedBy>);
}
#[derive_ReprC]
#[repr(transparent)]
pub struct SendHandle(pub VirtualPtr<dyn ISendHandle + Send + Sync>);
#[derive_ReprC(dyn, Clone)]
pub trait ISendHandle {
extern "C" fn cancel(&self) -> CancellationResult;
extern "C" fn poll(&self) -> SendStatus;
extern "C" fn set_on_change(&self, callback: Callback<SendStatus>, keep_previous: bool);
}
#[derive_ReprC]
#[repr(transparent)]
pub struct StreamInfo<'a>(pub VirtualPtr<dyn IStreamInfo + 'a>);
#[derive_ReprC(dyn)]
pub trait IStreamInfo {
extern "C" fn peer_pubkey(&self) -> PeerPubkey;
extern "C" fn topic(&self) -> safer_ffi::bytes::Bytes<'_>;
}
#[derive_ReprC]
#[repr(u8)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum StreamClosedBy {
Remote,
Local,
}
#[repr(C, u8)]
pub enum ConnectionResult {
Accepted(Stream) = 1,
Rejected(ConnectionError) = 0,
}
mod seal {
use super::*;
#[derive_ReprC]
#[repr(C)]
pub struct ConnectionResult_Layout {
pub accepted: bool,
pub stream: Stream,
}
unsafe impl ReprC for ConnectionResult {
type CLayout = CLayoutOf<ConnectionResult_Layout>;
fn is_valid(it: &'_ Self::CLayout) -> bool {
ConnectionResult_Layout::is_valid(it)
|| unsafe {
bool::is_valid(&it.accepted)
&& !core::mem::transmute::<_, bool>(it.accepted)
&& ConnectionError::is_valid(core::mem::transmute::<
&Stream_Layout,
&ConnectionError_Layout,
>(&it.stream))
}
}
}
#[test]
fn connection_result_layout() {
for expected in [
ConnectionResult::Rejected(ConnectionError::PeerNotFound),
ConnectionResult::Rejected(ConnectionError::TopicRejected),
] {
assert!(ConnectionResult::is_valid(&unsafe {
core::mem::transmute(expected)
}))
}
}
#[derive_ReprC]
#[repr(C)]
pub struct CancellationResult_Layout {
pub success: bool,
pub error_reason: CancellationError,
}
unsafe impl ReprC for CancellationResult {
type CLayout = CLayoutOf<CancellationResult_Layout>;
fn is_valid(it: &'_ Self::CLayout) -> bool {
CancellationResult_Layout::is_valid(it)
|| unsafe {
bool::is_valid(&it.success) && core::mem::transmute::<_, bool>(it.success)
}
}
}
#[test]
fn cancellation_result_layout() {
for expected in [
CancellationResult::Ok,
CancellationResult::Err(CancellationError::CancellationFailed),
] {
assert!(CancellationResult::is_valid(&unsafe {
core::mem::transmute(expected)
}))
}
assert!(CancellationResult::is_valid(&unsafe {
core::mem::transmute::<[bool; 2], CancellationResult_Layout_Layout>([false, false])
}));
assert!(CancellationResult::is_valid(&unsafe {
core::mem::transmute::<[bool; 2], CancellationResult_Layout_Layout>([true, false])
}));
assert!(!CancellationResult::is_valid(&unsafe {
core::mem::transmute::<[u8; 2], CancellationResult_Layout_Layout>([2, 0])
}));
assert!(!CancellationResult::is_valid(&unsafe {
core::mem::transmute::<[u8; 2], CancellationResult_Layout_Layout>([2, 1])
}));
assert!(!CancellationResult::is_valid(&unsafe {
core::mem::transmute::<[u8; 2], CancellationResult_Layout_Layout>([0, 1])
}));
}
}
#[derive_ReprC]
#[repr(u8)]
#[derive(thiserror::Error, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Clone, Copy)]
pub enum ConnectionError {
#[error("The peer you attempted to connect to was not found or failed to respond in time.")]
PeerNotFound,
#[error("The peer you attempted to connect to was found, but refused your topic.")]
TopicRejected,
}
#[derive_ReprC]
#[repr(u8)]
#[derive(thiserror::Error, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Clone, Copy)]
pub enum CancellationError {
#[error("Cancelling the send operation failed.")]
CancellationFailed,
}
#[repr(C, u8)]
pub enum CancellationResult {
Ok = 1,
Err(CancellationError) = 0,
}
impl From<Result<(), CancellationError>> for CancellationResult {
fn from(value: Result<(), CancellationError>) -> Self {
match value {
Ok(()) => Self::Ok,
Err(error) => Self::Err(error),
}
}
}
impl From<CancellationResult> for Result<(), CancellationError> {
fn from(value: CancellationResult) -> Self {
match value {
CancellationResult::Ok => Ok(()),
CancellationResult::Err(error) => Err(error),
}
}
}
#[derive_ReprC]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(u8)]
pub enum SendStatus {
Unknown = 0,
Pending = 1,
Sent = 2,
Failed = 3,
Cancelled = 4,
}
impl ISendHandle for SendStatus {
extern "C" fn cancel(&self) -> CancellationResult {
CancellationResult::Err(CancellationError::CancellationFailed)
}
extern "C" fn poll(&self) -> SendStatus {
*self
}
extern "C" fn set_on_change(
&self,
mut continuation: Callback<SendStatus>,
_keep_previous: bool,
) {
continuation.call(*self)
}
}
impl core::fmt::Debug for SendStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
SendStatus::Unknown => "SendStatus::Unknown",
SendStatus::Pending => "SendStatus::Pending",
SendStatus::Sent => "SendStatus::Sent",
SendStatus::Failed => "SendStatus::Failed",
SendStatus::Cancelled => "SendStatus::Cancelled",
};
f.write_str(s)
}
}
impl core::fmt::Display for SendStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
SendStatus::Unknown => "Unknown",
SendStatus::Pending => "Pending",
SendStatus::Sent => "Sent",
SendStatus::Failed => "Failed",
SendStatus::Cancelled => "Cancelled",
};
f.write_str(s)
}
}