use std::marker::PhantomData;
use crate::{
BindingDirection, CborPayload, ChannelId, ConnectionId, Metadata, MethodId, RequestId,
};
use facet::{Facet, FacetOpaqueAdapter, OpaqueDeserialize, OpaqueSerialize, PtrConst, Shape};
use vox_schema::opaque_encoded_borrowed;
#[derive(Debug, Clone, PartialEq, Eq, Facet)]
pub struct ConnectionSettings {
pub parity: Parity,
pub max_concurrent_requests: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SessionResumeKey(pub [u8; 16]);
impl<'payload> Message<'payload> {
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Facet)]
#[repr(u8)]
pub enum Parity {
Odd,
Even,
}
impl Parity {
pub fn other(self) -> Self {
match self {
Parity::Odd => Parity::Even,
Parity::Even => Parity::Odd,
}
}
}
structstruck::strike! {
#[structstruck::each[derive(Debug, Facet)]]
pub struct Message<'payload> {
pub connection_id: ConnectionId,
pub payload:
#[repr(u8)]
pub enum MessagePayload<'payload> {
ProtocolError(pub struct ProtocolError<'payload> {
/// Human-readable description of the protocol violation.
pub description: &'payload str,
}),
ConnectionOpen(pub struct ConnectionOpen<'payload> {
pub connection_settings: ConnectionSettings,
pub metadata: Metadata<'payload>,
}),
ConnectionAccept(pub struct ConnectionAccept<'payload> {
pub connection_settings: ConnectionSettings,
pub metadata: Metadata<'payload>,
}),
ConnectionReject(pub struct ConnectionReject<'payload> {
pub metadata: Metadata<'payload>,
}),
ConnectionClose(pub struct ConnectionClose<'payload> {
pub metadata: Metadata<'payload>,
}),
RequestMessage(
pub struct RequestMessage<'payload> {
pub id: RequestId,
pub body:
#[repr(u8)]
pub enum RequestBody<'payload> {
Call(pub struct RequestCall<'payload> {
/// Unique method identifier, hash of fully qualified name + args etc.
pub method_id: MethodId,
/// Metadata associated with this call
pub metadata: Metadata<'payload>,
/// Argument tuple
pub args: Payload<'payload>,
/// CBOR-encoded schemas for this call's args tuple
/// Non-empty on the first call for each method on a connection.
pub schemas: CborPayload,
}),
Response(struct RequestResponse<'payload> {
pub metadata: Metadata<'payload>,
pub ret: Payload<'payload>,
pub schemas: CborPayload,
}),
Cancel(struct RequestCancel<'payload> {
pub metadata: Metadata<'payload>,
}),
},
}
),
SchemaMessage(pub struct SchemaMessage {
pub method_id: MethodId,
pub direction: BindingDirection,
pub schemas: CborPayload,
}),
ChannelMessage(
pub struct ChannelMessage<'payload> {
pub id: ChannelId,
pub body:
#[repr(u8)]
pub enum ChannelBody<'payload> {
Item(pub struct ChannelItem<'payload> {
/// The item itself
pub item: Payload<'payload>,
}),
Close(pub struct ChannelClose<'payload> {
pub metadata: Metadata<'payload>,
}),
Reset(pub struct ChannelReset<'payload> {
pub metadata: Metadata<'payload>,
}),
GrantCredit(pub struct ChannelGrantCredit {
pub additional: u32,
}),
},
}
),
Ping(pub struct Ping {
pub nonce: u64,
}),
Pong(pub struct Pong {
pub nonce: u64,
}),
},
}
}
#[derive(Debug, Facet)]
#[repr(u8)]
#[facet(opaque = PayloadAdapter, traits(Debug))]
pub enum Payload<'payload> {
Value {
ptr: PtrConst,
shape: &'static Shape,
_lt: PhantomData<&'payload ()>,
},
PostcardBytes(&'payload [u8]),
}
impl<'payload> Payload<'payload> {
pub fn outgoing<T: Facet<'payload>>(value: &'payload T) -> Self {
unsafe {
Self::outgoing_unchecked(PtrConst::new((value as *const T).cast::<u8>()), T::SHAPE)
}
}
pub unsafe fn outgoing_unchecked(ptr: PtrConst, shape: &'static Shape) -> Self {
Self::Value {
ptr,
shape,
_lt: PhantomData,
}
}
pub fn reborrow(&self) -> Payload<'_> {
match self {
Payload::Value { ptr, shape, .. } => Payload::Value {
ptr: *ptr,
shape,
_lt: PhantomData,
},
Payload::PostcardBytes(bytes) => Payload::PostcardBytes(bytes),
}
}
}
unsafe impl<'payload> Send for Payload<'payload> {}
pub struct PayloadAdapter;
impl FacetOpaqueAdapter for PayloadAdapter {
type Error = String;
type SendValue<'a> = Payload<'a>;
type RecvValue<'de> = Payload<'de>;
fn serialize_map(value: &Self::SendValue<'_>) -> OpaqueSerialize {
match value {
Payload::Value { ptr, shape, .. } => OpaqueSerialize { ptr: *ptr, shape },
Payload::PostcardBytes(bytes) => opaque_encoded_borrowed(bytes),
}
}
fn deserialize_build<'de>(
input: OpaqueDeserialize<'de>,
) -> Result<Self::RecvValue<'de>, Self::Error> {
match input {
OpaqueDeserialize::Borrowed(bytes) => Ok(Payload::PostcardBytes(bytes)),
OpaqueDeserialize::Owned(_) => {
Err("payload bytes must be borrowed from backing, not owned".into())
}
}
}
}
pub struct MessageFamily;
impl crate::MsgFamily for MessageFamily {
type Msg<'a> = Message<'a>;
}
crate::impl_reborrow!(
Message,
RequestMessage,
RequestCall,
RequestResponse,
ConnectionOpen,
ConnectionAccept,
ConnectionReject,
ConnectionClose,
ChannelMessage,
ChannelItem,
ChannelClose,
ChannelReset,
);