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

Commit c7ea482

Browse files
committed
feat(rtc_types,byte_formats): add mod rkyv_format
1 parent 4b90c6f commit c7ea482

File tree

3 files changed

+111
-0
lines changed

3 files changed

+111
-0
lines changed

rtc_types/src/byte_formats/mod.rs

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

rtc_types/src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
// Used by rtc_types::byte_formats::rkyv_format
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")]

0 commit comments

Comments
 (0)