#![forbid(unsafe_code)]
use ridl_rt::contract::{
reservation, table_budget, CatalogHash, CatalogRef, Interaction, Interface, InterfaceNo, Kind,
Member, Ordinal, PayloadInfo, Sizes,
};
use ridl_rt::encoding::{Encoding, FlatBuffers};
use ridl_rt::payload::{EncodeError, Encoded, Malformed, Payload, Ref, VerifyError};
const CABIN: CatalogRef = CatalogRef {
name: "cabin",
hash: CatalogHash([3; 32]),
};
fn write_padded(value: u8, len: usize, out: &mut [u8]) -> Result<&[u8], EncodeError> {
let available = out.len();
let Some(front) = out.get_mut(..len) else {
return Err(EncodeError::Capacity {
needed: len,
available,
});
};
front.fill(0);
front[0] = value;
Ok(front)
}
fn read_padded(len: usize, buf: &[u8]) -> Result<&[u8], VerifyError> {
if buf.len() == len {
Ok(buf)
} else {
Err(VerifyError::Structure(Malformed::OutOfBounds))
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct Warning(u8);
impl Payload<FlatBuffers> for Warning {
const MAX_SIZE: usize = 8;
type Buffer = [u8; 8];
const BUFFER: [u8; 8] = [0; 8];
type View<'a> = &'a [u8];
fn encode<'o>(&self, out: &'o mut [u8]) -> Result<Encoded<'o, &'o [u8]>, EncodeError> {
let bytes = write_padded(self.0, Self::MAX_SIZE, out)?;
Ok(Encoded { bytes, view: bytes })
}
fn verify(buf: &[u8]) -> Result<&[u8], VerifyError> {
read_padded(Self::MAX_SIZE, buf)
}
fn decode(r: Ref<'_, Self, FlatBuffers>) -> Self {
Warning(r.bytes()[0])
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct Window(u8);
impl Payload<FlatBuffers> for Window {
const MAX_SIZE: usize = 24;
type Buffer = [u8; 24];
const BUFFER: [u8; 24] = [0; 24];
type View<'a> = &'a [u8];
fn encode<'o>(&self, out: &'o mut [u8]) -> Result<Encoded<'o, &'o [u8]>, EncodeError> {
let bytes = write_padded(self.0, Self::MAX_SIZE, out)?;
Ok(Encoded { bytes, view: bytes })
}
fn verify(buf: &[u8]) -> Result<&[u8], VerifyError> {
read_padded(Self::MAX_SIZE, buf)
}
fn decode(r: Ref<'_, Self, FlatBuffers>) -> Self {
Window(r.bytes()[0])
}
}
const WARNING: Member = Member {
ordinal: Ordinal(1),
kind: Kind::Event,
name: "warning",
timing: None,
payloads: &[PayloadInfo {
type_name: "Warning",
}],
};
const AVERAGE: Member = Member {
ordinal: Ordinal(2),
kind: Kind::Query,
name: "average",
timing: None,
payloads: &[
PayloadInfo {
type_name: "Window",
},
PayloadInfo {
type_name: "Warning",
},
],
};
const SET_WINDOW: Member = Member {
ordinal: Ordinal(3),
kind: Kind::Command,
name: "setWindow",
timing: None,
payloads: &[PayloadInfo {
type_name: "Window",
}],
};
struct Cabin;
impl Interface for Cabin {
const CATALOG: &'static CatalogRef = &CABIN;
const NUMBER: InterfaceNo = InterfaceNo(1);
const PROVISIONAL: bool = false;
const NAME: &'static str = "Cabin";
const MEMBERS: &'static [Member] = &[WARNING, AVERAGE, SET_WINDOW];
}
impl Sizes<FlatBuffers> for Cabin {
const RESERVATIONS: &'static [u64] = &[
<Warning as Payload<FlatBuffers>>::MAX_SIZE as u64,
<Window as Payload<FlatBuffers>>::MAX_SIZE as u64
+ <Warning as Payload<FlatBuffers>>::MAX_SIZE as u64,
<Window as Payload<FlatBuffers>>::MAX_SIZE as u64,
];
const MAX_BUFFER_SIZE: usize = <Window as Payload<FlatBuffers>>::MAX_SIZE;
const EVENT_SOURCE_BUFFER_SIZE: usize = <Warning as Payload<FlatBuffers>>::MAX_SIZE;
type ClaimBuffer = [u8; Self::MAX_BUFFER_SIZE];
type EventBuffer = [u8; Self::EVENT_SOURCE_BUFFER_SIZE];
const CLAIM_BUFFER: Self::ClaimBuffer = [0u8; Self::MAX_BUFFER_SIZE];
const EVENT_BUFFER: Self::EventBuffer = [0u8; Self::EVENT_SOURCE_BUFFER_SIZE];
}
struct CabinWarning;
impl Interaction for CabinWarning {
type Iface = Cabin;
const MEMBER: &'static Member = &Cabin::MEMBERS[0];
const ROW: usize = 0;
}
struct CabinAverage;
impl Interaction for CabinAverage {
type Iface = Cabin;
const MEMBER: &'static Member = &Cabin::MEMBERS[1];
const ROW: usize = 1;
}
struct CabinSetWindow;
impl Interaction for CabinSetWindow {
type Iface = Cabin;
const MEMBER: &'static Member = &Cabin::MEMBERS[2];
const ROW: usize = 2;
}
struct Huge;
impl Interface for Huge {
const CATALOG: &'static CatalogRef = &CABIN;
const NUMBER: InterfaceNo = InterfaceNo(2);
const PROVISIONAL: bool = false;
const NAME: &'static str = "Huge";
const MEMBERS: &'static [Member] = &[SET_WINDOW, WARNING];
}
impl Sizes<FlatBuffers> for Huge {
const RESERVATIONS: &'static [u64] = &[u64::MAX, 1];
const MAX_BUFFER_SIZE: usize = 0;
const EVENT_SOURCE_BUFFER_SIZE: usize = 0;
type ClaimBuffer = [u8; 0];
type EventBuffer = [u8; 0];
const CLAIM_BUFFER: Self::ClaimBuffer = [];
const EVENT_BUFFER: Self::EventBuffer = [];
}
struct Empty;
impl Interface for Empty {
const CATALOG: &'static CatalogRef = &CABIN;
const NUMBER: InterfaceNo = InterfaceNo(3);
const PROVISIONAL: bool = false;
const NAME: &'static str = "Empty";
const MEMBERS: &'static [Member] = &[];
}
impl Sizes<FlatBuffers> for Empty {
const RESERVATIONS: &'static [u64] = &[];
const MAX_BUFFER_SIZE: usize = 0;
const EVENT_SOURCE_BUFFER_SIZE: usize = 0;
type ClaimBuffer = [u8; 0];
type EventBuffer = [u8; 0];
const CLAIM_BUFFER: Self::ClaimBuffer = [];
const EVENT_BUFFER: Self::EventBuffer = [];
}
struct Wide;
impl Interface for Wide {
const CATALOG: &'static CatalogRef = &CABIN;
const NUMBER: InterfaceNo = InterfaceNo(4);
const PROVISIONAL: bool = false;
const NAME: &'static str = "Wide";
const MEMBERS: &'static [Member] = &[AVERAGE];
}
impl Sizes<FlatBuffers> for Wide {
const RESERVATIONS: &'static [u64] = &[(u32::MAX as usize) as u64 + (u32::MAX as usize) as u64];
const MAX_BUFFER_SIZE: usize = 0;
const EVENT_SOURCE_BUFFER_SIZE: usize = 0;
type ClaimBuffer = [u8; 0];
type EventBuffer = [u8; 0];
const CLAIM_BUFFER: Self::ClaimBuffer = [];
const EVENT_BUFFER: Self::EventBuffer = [];
}
struct WideAverage;
impl Interaction for WideAverage {
type Iface = Wide;
const MEMBER: &'static Member = &Wide::MEMBERS[0];
const ROW: usize = 0;
}
#[test]
fn a_reservation_is_the_interactions_row() {
assert_eq!(reservation::<CabinAverage, FlatBuffers>(), 32);
assert_eq!(reservation::<CabinWarning, FlatBuffers>(), 8);
assert_eq!(reservation::<CabinSetWindow, FlatBuffers>(), 24);
}
#[test]
fn a_row_indexes_the_descriptors_member() {
fn row_is_member<X: Interaction>() {
assert_eq!(
<X::Iface as Interface>::MEMBERS[X::ROW],
*X::MEMBER,
"{}",
X::MEMBER.name
);
}
row_is_member::<CabinWarning>();
row_is_member::<CabinAverage>();
row_is_member::<CabinSetWindow>();
}
#[test]
fn a_table_budget_sums_every_row() {
assert_eq!(table_budget::<Cabin, FlatBuffers>(), 64);
}
#[test]
fn an_empty_table_has_a_budget_of_zero() {
assert_eq!(table_budget::<Empty, FlatBuffers>(), 0);
}
#[test]
fn the_sum_is_wider_than_one_size() {
assert_eq!(
reservation::<WideAverage, FlatBuffers>(),
2 * u64::from(u32::MAX)
);
assert_eq!(table_budget::<Wide, FlatBuffers>(), 2 * u64::from(u32::MAX));
}
#[test]
fn a_table_budget_saturates() {
assert_eq!(table_budget::<Huge, FlatBuffers>(), u64::MAX);
}
#[test]
fn a_static_table_is_sized_from_the_budget() {
static TABLE: [u8; table_budget::<Cabin, FlatBuffers>() as usize] =
[0; table_budget::<Cabin, FlatBuffers>() as usize];
static ROW: [u8; reservation::<CabinAverage, FlatBuffers>() as usize] =
[0; reservation::<CabinAverage, FlatBuffers>() as usize];
assert_eq!(TABLE.len(), 64);
assert_eq!(ROW.len(), 32);
}
fn hold<I: Sizes<E>, E: Encoding>() -> (usize, usize) {
let mut claim = I::CLAIM_BUFFER;
let mut event = I::EVENT_BUFFER;
assert!(claim.as_ref().iter().all(|byte| *byte == 0));
assert!(event.as_ref().iter().all(|byte| *byte == 0));
(claim.as_mut().len(), event.as_mut().len())
}
#[test]
fn the_claim_and_event_buffers_have_the_interface_maxima() {
assert_eq!(hold::<Cabin, FlatBuffers>(), (24, 8));
}
fn register(members: &'static [Member], rows: &'static [u64]) -> u64 {
assert_eq!(members.len(), rows.len());
rows.iter().sum()
}
#[test]
fn a_data_driven_runtime_registers_the_slice() {
assert_eq!(
register(Cabin::MEMBERS, <Cabin as Sizes<FlatBuffers>>::RESERVATIONS),
64
);
}