use crate::prelude::IPCResult; use byteorder::{BigEndian, ReadBytesExt}; use bytes::{BufMut, Bytes, BytesMut}; use std::io::Read; #[cfg(feature = "serialize")] pub use super::payload_serializer::*; /// Trait that serializes a type into bytes and can fail pub trait TryIntoBytes { fn try_into_bytes(self) -> IPCResult; } /// Trait to convert event data into sending bytes /// It is implemented for all types that implement Serialize pub trait IntoPayload { fn into_payload(self, ctx: &Context) -> IPCResult; } /// Trait to get the event data from receiving bytes. /// It is implemented for all types that are DeserializeOwned pub trait FromPayload: Sized { fn from_payload(reader: R) -> IPCResult; } /// A payload wrapper type for sending bytes directly without /// serializing them #[derive(Clone)] pub struct BytePayload { bytes: Bytes, } impl BytePayload { #[inline] pub fn new(bytes: Vec) -> Self { Self { bytes: Bytes::from(bytes), } } /// Returns the bytes as a `Vec` of the payload #[inline] pub fn into_inner(self) -> Vec { self.bytes.to_vec() } /// Returns the bytes struct of the payload #[inline] pub fn into_bytes(self) -> Bytes { self.bytes } } impl From for BytePayload { fn from(bytes: Bytes) -> Self { Self { bytes } } } impl IntoPayload for BytePayload { #[inline] fn into_payload(self, _: &Context) -> IPCResult { Ok(self.bytes) } } impl FromPayload for BytePayload { #[inline] fn from_payload(mut reader: R) -> IPCResult { let mut buf = Vec::new(); reader.read_to_end(&mut buf)?; Ok(Self::new(buf)) } } /// A payload wrapper that allows storing two different payloads /// independent from each other. For example one payload can be /// a payload serialized by serde while the other is a raw byte /// payload pub struct TandemPayload { load1: P1, load2: P2, } impl TandemPayload { #[inline] pub fn new(load1: P1, load2: P2) -> Self { Self { load1, load2 } } /// Returns both payload stored in the tandem payload #[inline] pub fn into_inner(self) -> (P1, P2) { (self.load1, self.load2) } } impl IntoPayload for TandemPayload { fn into_payload(self, ctx: &Context) -> IPCResult { let p1_bytes = self.load1.into_payload(&ctx)?; let p2_bytes = self.load2.into_payload(&ctx)?; let mut bytes = BytesMut::with_capacity(p1_bytes.len() + p2_bytes.len() + 16); bytes.put_u64(p1_bytes.len() as u64); bytes.put(p1_bytes); bytes.put_u64(p2_bytes.len() as u64); bytes.put(p2_bytes); Ok(bytes.freeze()) } } impl FromPayload for TandemPayload { fn from_payload(mut reader: R) -> IPCResult { let p1_length = reader.read_u64::()?; let mut load1_bytes = vec![0u8; p1_length as usize]; reader.read_exact(&mut load1_bytes)?; let p2_length = reader.read_u64::()?; let mut load2_bytes = vec![0u8; p2_length as usize]; reader.read_exact(&mut load2_bytes)?; Ok(Self { load1: P1::from_payload(load1_bytes.as_slice())?, load2: P2::from_payload(load2_bytes.as_slice())?, }) } } #[cfg(not(feature = "serialize"))] impl IntoPayload for () { fn into_payload(self, _: &Context) -> IPCResult { Ok(Bytes::new()) } } #[cfg(feature = "serialize")] mod serde_payload { use super::DynamicSerializer; use crate::context::Context; use crate::payload::{FromPayload, TryIntoBytes}; use crate::prelude::{IPCResult, IntoPayload}; use byteorder::ReadBytesExt; use bytes::{BufMut, Bytes, BytesMut}; use serde::de::DeserializeOwned; use serde::Serialize; use std::io::Read; /// A payload representing a payload storing serde serialized data pub struct SerdePayload { data: T, serializer: DynamicSerializer, } impl SerdePayload { /// Creates a new serde payload with a specified serializer #[inline] pub fn new(serializer: DynamicSerializer, data: T) -> Self { Self { serializer, data } } #[inline] pub fn data(self) -> T { self.data } } impl Clone for SerdePayload { fn clone(&self) -> Self { Self { serializer: self.serializer.clone(), data: self.data.clone(), } } } impl TryIntoBytes for SerdePayload { fn try_into_bytes(self) -> IPCResult { let mut buf = BytesMut::new(); let data_bytes = self.serializer.serialize(self.data)?; let format_id = self.serializer as u8; buf.put_u8(format_id); buf.put(data_bytes); Ok(buf.freeze()) } } impl IntoPayload for SerdePayload { #[inline] fn into_payload(self, _: &Context) -> IPCResult { self.try_into_bytes() } } impl FromPayload for SerdePayload { fn from_payload(mut reader: R) -> IPCResult { let format_id = reader.read_u8()?; let serializer = DynamicSerializer::from_primitive(format_id as usize)?; let data = serializer.deserialize(reader)?; Ok(Self { serializer, data }) } } impl IntoPayload for T { #[inline] fn into_payload(self, ctx: &Context) -> IPCResult { ctx.create_serde_payload(self).into_payload(&ctx) } } impl FromPayload for T { #[inline] fn from_payload(reader: R) -> IPCResult { let serde_payload = SerdePayload::::from_payload(reader)?; Ok(serde_payload.data) } } } use crate::context::Context; #[cfg(feature = "serialize")] pub use serde_payload::*;