use crate::encoding::{
AtRestFlags, Context, Decode, Decoder, Depth, Encode, Encoder, GenericMessage,
GenericMessageType, HandleFor, NoHandleResourceDialect, ProxyChannelFor, ResourceDialect,
ResourceTypeMarker, TypeMarker, ValueTypeMarker, WireFormatVersion, MAGIC_NUMBER_INITIAL,
};
use crate::{Error, Result};
pub trait Persistable:
TypeMarker<Owned = Self>
+ Decode<Self, NoHandleResourceDialect>
+ for<'a> ValueTypeMarker<Borrowed<'a> = &'a Self>
+ for<'a> ValueTypeMarker<Borrowed<'a>: Encode<Self, NoHandleResourceDialect>>
{
}
pub trait Standalone<D>:
TypeMarker<Owned = Self> + Decode<Self, D> + for<'a> ResourceTypeMarker<Borrowed<'a> = &'a mut Self>
{
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(C)]
pub struct WireMetadata {
disambiguator: u8,
magic_number: u8,
at_rest_flags: [u8; 2],
reserved: [u8; 4],
}
impl WireMetadata {
#[inline]
fn new_full(context: Context, magic_number: u8) -> Self {
WireMetadata {
disambiguator: 0,
magic_number,
at_rest_flags: context.at_rest_flags().into(),
reserved: [0; 4],
}
}
#[inline]
fn at_rest_flags(&self) -> AtRestFlags {
AtRestFlags::from_bits_truncate(u16::from_le_bytes(self.at_rest_flags))
}
#[inline]
fn decoding_context(&self) -> Context {
Context { wire_format_version: WireFormatVersion::V2 }
}
#[inline]
pub fn validate_wire_format(&self) -> Result<()> {
if self.magic_number != MAGIC_NUMBER_INITIAL {
return Err(Error::IncompatibleMagicNumber(self.magic_number));
}
if !self.at_rest_flags().contains(AtRestFlags::USE_V2_WIRE_FORMAT) {
return Err(Error::UnsupportedWireFormatVersion);
}
Ok(())
}
}
#[inline]
fn default_persistent_encode_context() -> Context {
Context { wire_format_version: WireFormatVersion::V2 }
}
pub fn persist<T: Persistable>(body: &T) -> Result<Vec<u8>> {
let context = default_persistent_encode_context();
let header = WireMetadata::new_full(context, MAGIC_NUMBER_INITIAL);
let msg = GenericMessage { header, body };
let mut bytes = Vec::<u8>::new();
let mut handles = Vec::new();
Encoder::encode_with_context::<GenericMessageType<WireMetadata, T>>(
context,
&mut bytes,
&mut handles,
msg,
)?;
debug_assert!(handles.is_empty(), "value type contains handles");
Ok(bytes)
}
pub fn unpersist<T: Persistable>(bytes: &[u8]) -> Result<T> {
let (header, body_bytes) = decode_wire_metadata(bytes)?;
let mut output = T::new_empty();
Decoder::decode_with_context::<T>(header.decoding_context(), body_bytes, &mut [], &mut output)?;
Ok(output)
}
pub fn standalone_encode_value<T: Persistable>(body: &T) -> Result<(Vec<u8>, WireMetadata)>
where
for<'a> T::Borrowed<'a>: Encode<T, NoHandleResourceDialect>,
{
fn helper<T: ValueTypeMarker>(body: T::Borrowed<'_>) -> Result<(Vec<u8>, WireMetadata)>
where
for<'a> T::Borrowed<'a>: Encode<T, NoHandleResourceDialect>,
{
let context = default_persistent_encode_context();
let metadata = WireMetadata::new_full(context, MAGIC_NUMBER_INITIAL);
let mut bytes = Vec::<u8>::new();
let mut handles = Vec::new();
Encoder::<NoHandleResourceDialect>::encode_with_context::<T>(
context,
&mut bytes,
&mut handles,
body,
)?;
debug_assert!(handles.is_empty(), "value type contains handles");
Ok((bytes, metadata))
}
helper::<T>(body)
}
#[allow(clippy::type_complexity)]
pub fn standalone_encode_resource<T: Standalone<D>, D: ResourceDialect>(
mut body: T,
) -> Result<(Vec<u8>, Vec<<D::ProxyChannel as ProxyChannelFor<D>>::HandleDisposition>, WireMetadata)>
where
for<'a> T::Borrowed<'a>: Encode<T, D>,
{
let context = default_persistent_encode_context();
let metadata = WireMetadata::new_full(context, MAGIC_NUMBER_INITIAL);
let mut bytes = Vec::<u8>::new();
let mut handles = Vec::<_>::new();
Encoder::encode_with_context::<T>(context, &mut bytes, &mut handles, &mut body)?;
Ok((bytes, handles, metadata))
}
pub fn standalone_decode_value<T: Persistable>(bytes: &[u8], metadata: &WireMetadata) -> Result<T> {
let mut output = T::Owned::new_empty();
Decoder::decode_with_context::<T>(metadata.decoding_context(), bytes, &mut [], &mut output)?;
Ok(output)
}
pub fn standalone_decode_resource<T: Standalone<D>, D: ResourceDialect>(
bytes: &[u8],
handles: &mut [<D::Handle as HandleFor<D>>::HandleInfo],
metadata: &WireMetadata,
) -> Result<T> {
let mut output = <T as TypeMarker>::Owned::new_empty();
Decoder::decode_with_context::<T>(metadata.decoding_context(), bytes, handles, &mut output)?;
Ok(output)
}
fn decode_wire_metadata(bytes: &[u8]) -> Result<(WireMetadata, &[u8])> {
let mut header = new_empty!(WireMetadata, NoHandleResourceDialect);
let context = Context { wire_format_version: WireFormatVersion::V2 };
let header_len = <WireMetadata as TypeMarker>::inline_size(context);
if bytes.len() < header_len {
return Err(Error::OutOfRange);
}
let (header_bytes, body_bytes) = bytes.split_at(header_len);
Decoder::<NoHandleResourceDialect>::decode_with_context::<WireMetadata>(
context,
header_bytes,
&mut [],
&mut header,
)
.map_err(|_| Error::InvalidHeader)?;
header.validate_wire_format()?;
Ok((header, body_bytes))
}
unsafe impl TypeMarker for WireMetadata {
type Owned = Self;
#[inline(always)]
fn inline_align(_context: Context) -> usize {
1
}
#[inline(always)]
fn inline_size(_context: Context) -> usize {
8
}
}
impl ValueTypeMarker for WireMetadata {
type Borrowed<'a> = &'a Self;
fn borrow(value: &<Self as TypeMarker>::Owned) -> Self::Borrowed<'_> {
value
}
}
unsafe impl<D: ResourceDialect> Encode<WireMetadata, D> for &WireMetadata {
#[inline]
unsafe fn encode(
self,
encoder: &mut Encoder<'_, D>,
offset: usize,
_depth: Depth,
) -> Result<()> {
encoder.debug_check_bounds::<WireMetadata>(offset);
unsafe {
let buf_ptr = encoder.buf.as_mut_ptr().add(offset);
(buf_ptr as *mut WireMetadata).write_unaligned(*self);
}
Ok(())
}
}
impl<D: ResourceDialect> Decode<Self, D> for WireMetadata {
#[inline(always)]
fn new_empty() -> Self {
Self { disambiguator: 0, magic_number: 0, at_rest_flags: [0; 2], reserved: [0; 4] }
}
#[inline]
unsafe fn decode(
&mut self,
decoder: &mut Decoder<'_, D>,
offset: usize,
_depth: Depth,
) -> Result<()> {
decoder.debug_check_bounds::<Self>(offset);
unsafe {
let buf_ptr = decoder.buf.as_ptr().add(offset);
let obj_ptr = self as *mut WireMetadata;
std::ptr::copy_nonoverlapping(buf_ptr, obj_ptr as *mut u8, 8);
}
Ok(())
}
}