Skip to content
This repository was archived by the owner on May 9, 2022. It is now read-only.

Commit 7e2cad3

Browse files
committed
feat(rtc_types,binhelpers): add binhelpers module, supporting rkyv
1 parent 2c3ce27 commit 7e2cad3

File tree

2 files changed

+134
-0
lines changed

2 files changed

+134
-0
lines changed

rtc_types/src/binhelpers.rs

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
//! Binary data serialization helpers
2+
//!
3+
//! # Naming convention
4+
//!
5+
//! Functions in this module use the following naming convention:
6+
//!
7+
//! > `{format}_(write|read|view)_(array|slice)`
8+
//!
9+
//! 1. Format prefix, identifying the binary format (or library):
10+
//!
11+
//! - [`rkyv`]
12+
//!
13+
//! 2. Operation:
14+
//!
15+
//! - `write` to serialize a structure to bytes
16+
//! - `read` to deserialize bytes to a new Rust structure (copying data)
17+
//! - `view` to deserialize bytes to a structured view (sharing data)
18+
//!
19+
//! 3. Type suffix, for the binary data representation:
20+
//!
21+
//! - `array` for working with constant-sized arrays (`[u8; ?]`)
22+
//! - `slice` for working with variable-sized slices (`[u8]`)
23+
24+
use core::mem::size_of;
25+
26+
use rkyv::{
27+
archived_root,
28+
ser::{
29+
serializers::{BufferSerializer, BufferSerializerError},
30+
Serializer,
31+
},
32+
Aligned, Archive, Deserialize, Infallible, Serialize, Unreachable,
33+
};
34+
35+
pub fn rkyv_write_array<T>(
36+
value: &T,
37+
) -> Result<[u8; size_of::<T::Archived>()], BufferSerializerError>
38+
where
39+
T: Serialize<BufferSerializer<Aligned<[u8; size_of::<T::Archived>()]>>>,
40+
{
41+
let mut serializer = BufferSerializer::new(Aligned([0u8; size_of::<T::Archived>()]));
42+
serializer.serialize_value(value)?;
43+
let buf = serializer.into_inner();
44+
Ok(buf.0)
45+
}
46+
47+
/// # Safety
48+
///
49+
/// This does not perform input validation, and may have undefined behaviour for untrusted input.
50+
///
51+
/// See safety of [`archived_root`]:
52+
///
53+
/// > The caller must guarantee that the byte slice represents an archived object and that the root
54+
/// > object is stored at the end of the byte slice.
55+
///
56+
/// TODO: Use `check_archived_root` once it's stable without `std` (rkyv 0.7.0?).
57+
/// See issue: [no_std validation #107](https://github.com/djkoloski/rkyv/issues/107)
58+
pub unsafe fn rkyv_view_array<T>(bytes: &[u8; size_of::<T::Archived>()]) -> &T::Archived
59+
where
60+
T: Archive,
61+
{
62+
archived_root::<T>(bytes)
63+
}
64+
65+
/// # Safety
66+
///
67+
/// See safety of [`rkyv_view_array`].
68+
pub unsafe fn rkyv_read_array<T>(bytes: &[u8; size_of::<T::Archived>()]) -> T
69+
where
70+
T: Archive,
71+
T::Archived: Deserialize<T, Infallible>,
72+
{
73+
let archived = rkyv_view_array::<T>(bytes);
74+
let result: Result<T, Unreachable> = archived.deserialize(&mut Infallible);
75+
// Safety: this should not allocate, so it should not fail.
76+
result.expect("rkyv_read_array: unexpected deserialize failure!")
77+
}
78+
79+
#[cfg(test)]
80+
mod tests {
81+
use core::mem::{size_of, size_of_val};
82+
83+
use rkyv::{Archive, Deserialize, Serialize};
84+
85+
use super::*;
86+
87+
use proptest::prelude::*;
88+
use proptest_derive::Arbitrary;
89+
90+
/// Arbitrary structure to test with.
91+
#[derive(
92+
Debug,
93+
PartialEq,
94+
// rkyv:
95+
Archive,
96+
Deserialize,
97+
Serialize,
98+
// proptest:
99+
Arbitrary,
100+
)]
101+
struct Foo {
102+
byte: u8,
103+
int: u32,
104+
opt: Option<i32>,
105+
ary: [u8; 16],
106+
}
107+
108+
const ARCHIVED_FOO_SIZE: usize = size_of::<ArchivedFoo>();
109+
110+
/// [`rkyv_write_array`] roundtrips with [`rkyv_view_array`] and [`rkyv_read_array`].
111+
#[test]
112+
fn prop_rkyv_array_roundtrip() {
113+
let test = |value: &Foo| {
114+
let bytes = &rkyv_write_array(value).unwrap();
115+
assert_eq!(size_of_val(bytes), ARCHIVED_FOO_SIZE);
116+
117+
let view = unsafe { rkyv_view_array::<Foo>(bytes) };
118+
assert_eq!(value.byte, view.byte);
119+
assert_eq!(value.int, view.int);
120+
assert_eq!(value.opt, view.opt);
121+
assert_eq!(value.ary, view.ary);
122+
123+
let read = &unsafe { rkyv_read_array(bytes) };
124+
assert_eq!(value, read);
125+
};
126+
proptest!(|(value: Foo)| test(&value));
127+
}
128+
}

rtc_types/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
// Used by: rtc_types::binhelpers
2+
#![allow(incomplete_features)]
3+
#![feature(const_generics)]
4+
#![feature(const_evaluatable_checked)]
15
// TODO: Document
26
#![cfg_attr(feature = "teaclave_sgx", no_std)]
37
#[cfg(feature = "teaclave_sgx")]
@@ -25,6 +29,8 @@ pub use exec_token::*;
2529
mod ecall_result;
2630
pub use ecall_result::*;
2731

32+
pub mod binhelpers;
33+
2834
#[repr(C)]
2935
#[derive(Clone, Debug)]
3036
pub struct EncryptedMessage {

0 commit comments

Comments
 (0)