use crate::encoding::Encoding;
use crate::sample::Duration;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Ordinal(pub u32);
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct InterfaceNo(pub u32);
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct CatalogHash(pub [u8; 32]);
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct CatalogRef {
pub name: &'static str,
pub hash: CatalogHash,
}
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum Kind {
Signal = 1,
Event = 2,
Command = 3,
Query = 4,
Fixed = 5,
}
pub trait Interface {
const CATALOG: &'static CatalogRef;
const NUMBER: InterfaceNo;
const PROVISIONAL: bool;
const NAME: &'static str;
const MEMBERS: &'static [Member];
}
pub trait Interaction {
type Iface: Interface;
const MEMBER: &'static Member;
const ROW: usize;
}
pub trait Sizes<E: Encoding>: Interface {
const RESERVATIONS: &'static [u64];
const MAX_BUFFER_SIZE: usize;
const EVENT_SOURCE_BUFFER_SIZE: usize;
type ClaimBuffer: AsRef<[u8]> + AsMut<[u8]> + Copy;
type EventBuffer: AsRef<[u8]> + AsMut<[u8]> + Copy;
const CLAIM_BUFFER: Self::ClaimBuffer;
const EVENT_BUFFER: Self::EventBuffer;
}
pub const fn reservation<X, E>() -> u64
where
X: Interaction,
X::Iface: Sizes<E>,
E: Encoding,
{
<X::Iface as Sizes<E>>::RESERVATIONS[X::ROW]
}
pub const fn table_budget<I: Sizes<E>, E: Encoding>() -> u64 {
let rows = I::RESERVATIONS;
let mut total: u64 = 0;
let mut i = 0;
while i < rows.len() {
total = total.saturating_add(rows[i]);
i += 1;
}
total
}
pub trait Signal: Interaction {
type Payload;
fn init() -> Self::Payload;
}
pub trait Event: Interaction {
type Payload;
}
pub trait Fixed: Interaction {
type Payload;
}
pub trait Command: Interaction {
type Args;
#[allow(
clippy::result_unit_err,
reason = "the failing method decides the contract error, so the error carries no value"
)]
fn require(args: &Self::Args) -> Result<(), ()>;
}
pub trait Query: Interaction {
type Args;
type Reply;
#[allow(
clippy::result_unit_err,
reason = "the failing method decides the contract error, so the error carries no value"
)]
fn require(args: &Self::Args) -> Result<(), ()>;
#[allow(
clippy::result_unit_err,
reason = "the failing method decides the contract error, so the error carries no value"
)]
fn ensure(args: &Self::Args, reply: &Self::Reply) -> Result<(), ()>;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Member {
pub ordinal: Ordinal,
pub kind: Kind,
pub name: &'static str,
pub timing: Option<Timing>,
pub payloads: &'static [PayloadInfo],
}
impl Member {
pub fn call_deadline(&self) -> Option<Duration> {
self.timing.and_then(|timing| timing.max)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TimingMode {
StrictPeriodic,
Range,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Timing {
pub mode: TimingMode,
pub min: Option<Duration>,
pub max: Option<Duration>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct PayloadInfo {
pub type_name: &'static str,
}
#[cfg(test)]
mod tests {
use super::{CatalogHash, CatalogRef, Kind};
#[test]
fn catalog_refs_are_equal_only_when_name_and_hash_are_equal() {
let base = CatalogRef {
name: "vehicle",
hash: CatalogHash([1; 32]),
};
let same = CatalogRef {
name: "vehicle",
hash: CatalogHash([1; 32]),
};
let other_hash = CatalogRef {
name: "vehicle",
hash: CatalogHash([2; 32]),
};
let other_name = CatalogRef {
name: "cabin",
hash: CatalogHash([1; 32]),
};
assert_eq!(base, same);
assert_ne!(base, other_hash);
assert_ne!(base, other_name);
}
#[test]
fn kind_values_are_the_language_order_from_one() {
assert_eq!(Kind::Signal as u8, 1);
assert_eq!(Kind::Event as u8, 2);
assert_eq!(Kind::Command as u8, 3);
assert_eq!(Kind::Query as u8, 4);
assert_eq!(Kind::Fixed as u8, 5);
}
}