use std::sync::{Arc, Mutex};
use std::task::Waker;
use ridl_rt::contract::{CatalogRef, InterfaceNo, Ordinal};
use ridl_rt::encoding::{Encoding, FlatBuffers};
use ridl_rt::error::CallError;
use ridl_rt::port::{
Attached, Caller, Changed, Claim, ClaimId, Clock, CoherentSignals, Correlation, Encoded,
EventSink, EventSource, FixedReader, Handler, Interest, RaiseError, RawOccurrence, RawSample,
ReadError, ScannableSignals, SendError, ServeError, SettleError, SignalReader, SignalWriter,
SubscribeError, Wakeable, Watermark, WriteError,
};
use ridl_rt::sample::{Duration, Timestamp};
use ridl_rt::trace::TraceContext;
mod handle;
mod store;
pub use handle::{
CallerHandle, HandlerHandle, ReaderHandle, SinkHandle, SourceHandle, WriterHandle,
};
use handle::{lock, Shared};
use store::Store;
pub struct Handles<E: Encoding = FlatBuffers> {
pub reader: ReaderHandle<E>,
pub writer: WriterHandle<E>,
pub source: SourceHandle<E>,
pub sink: SinkHandle<E>,
pub caller: CallerHandle<E>,
pub handler: HandlerHandle<E>,
}
pub struct Loopback<E: Encoding = FlatBuffers> {
shared: Shared,
catalog: CatalogRef,
handles: Handles<E>,
}
impl Loopback<FlatBuffers> {
pub const SLOTS: usize = store::SLOTS;
#[must_use]
pub fn new(catalog: CatalogRef) -> Self {
Loopback::<FlatBuffers>::with_encoding(catalog)
}
}
impl<E: Encoding> Loopback<E> {
#[must_use]
pub fn with_encoding(catalog: CatalogRef) -> Self {
Loopback::over(Arc::new(Mutex::new(Store::new())), catalog)
}
fn over(shared: Shared, catalog: CatalogRef) -> Self {
let handles = Handles {
reader: ReaderHandle::new(Arc::clone(&shared), catalog),
writer: WriterHandle::new(Arc::clone(&shared), catalog),
source: SourceHandle::new(Arc::clone(&shared), catalog),
sink: SinkHandle::new(Arc::clone(&shared), catalog),
caller: CallerHandle::new(Arc::clone(&shared), catalog),
handler: HandlerHandle::new(Arc::clone(&shared), catalog),
};
Loopback {
shared,
catalog,
handles,
}
}
#[must_use]
pub fn split(self) -> Handles<E> {
self.handles
}
#[must_use]
pub fn attach(&self) -> Loopback<E> {
Loopback::over(Arc::clone(&self.shared), self.catalog)
}
#[must_use]
pub fn reader(&self) -> ReaderHandle<E> {
ReaderHandle::new(Arc::clone(&self.shared), self.catalog)
}
#[must_use]
pub fn writer(&self) -> WriterHandle<E> {
WriterHandle::new(Arc::clone(&self.shared), self.catalog)
}
#[must_use]
pub fn source(&self) -> SourceHandle<E> {
SourceHandle::new(Arc::clone(&self.shared), self.catalog)
}
#[must_use]
pub fn sink(&self) -> SinkHandle<E> {
SinkHandle::new(Arc::clone(&self.shared), self.catalog)
}
#[must_use]
pub fn caller(&self) -> CallerHandle<E> {
CallerHandle::new(Arc::clone(&self.shared), self.catalog)
}
#[must_use]
pub fn handler(&self) -> HandlerHandle<E> {
HandlerHandle::new(Arc::clone(&self.shared), self.catalog)
}
pub fn advance(&mut self, by: Duration) {
lock(&self.shared).advance(by);
}
pub fn provision_fixed(&mut self, iface: InterfaceNo, ord: Ordinal, bytes: &[u8]) {
lock(&self.shared).provision_fixed(iface, ord, bytes);
}
pub fn fail_next_settle(&mut self) {
lock(&self.shared).fail_next_settle();
}
}
impl<E: Encoding> Attached for Loopback<E> {
fn catalog(&self) -> &CatalogRef {
self.handles.reader.catalog()
}
}
impl<E: Encoding> Encoded for Loopback<E> {
type Encoding = E;
}
impl<E: Encoding> Clock for Loopback<E> {
fn now(&self) -> Timestamp {
self.handles.reader.now()
}
}
impl<E: Encoding> SignalReader for Loopback<E> {
fn read(
&self,
iface: InterfaceNo,
ord: Ordinal,
out: &mut [u8],
) -> Result<RawSample, ReadError> {
self.handles.reader.read(iface, ord, out)
}
}
impl<E: Encoding> FixedReader for Loopback<E> {
fn read_fixed(
&self,
iface: InterfaceNo,
ord: Ordinal,
out: &mut [u8],
) -> Result<usize, ReadError> {
self.handles.reader.read_fixed(iface, ord, out)
}
}
impl<E: Encoding> ScannableSignals for Loopback<E> {
fn generation(&self, iface: InterfaceNo) -> u64 {
self.handles.reader.generation(iface)
}
fn scan(&self, marks: &mut [Watermark], out: &mut [Changed]) -> usize {
self.handles.reader.scan(marks, out)
}
}
impl<E: Encoding> CoherentSignals for Loopback<E> {
fn read_coherent(
&self,
iface: InterfaceNo,
ords: &[Ordinal],
out: &mut [u8],
samples: &mut [RawSample],
) -> Result<usize, ReadError> {
self.handles.reader.read_coherent(iface, ords, out, samples)
}
}
impl<E: Encoding> SignalWriter for Loopback<E> {
fn set(&mut self, iface: InterfaceNo, ord: Ordinal, bytes: &[u8]) -> Result<(), WriteError> {
self.handles.writer.set(iface, ord, bytes)
}
fn invalidate(&mut self, iface: InterfaceNo, ord: Ordinal) -> Result<(), WriteError> {
self.handles.writer.invalidate(iface, ord)
}
fn touch(&mut self, iface: InterfaceNo, ord: Ordinal) -> Result<(), WriteError> {
self.handles.writer.touch(iface, ord)
}
fn commit(&mut self) {
self.handles.writer.commit();
}
}
impl<E: Encoding> EventSource for Loopback<E> {
fn subscribe(&mut self, iface: InterfaceNo, ords: &[Ordinal]) -> Result<(), SubscribeError> {
self.handles.source.subscribe(iface, ords)
}
fn unsubscribe(&mut self, iface: InterfaceNo, ords: &[Ordinal]) {
self.handles.source.unsubscribe(iface, ords);
}
fn next(&mut self, out: &mut [u8]) -> Result<Option<RawOccurrence>, ReadError> {
self.handles.source.next(out)
}
}
impl<E: Encoding> EventSink for Loopback<E> {
fn raise(
&mut self,
iface: InterfaceNo,
ord: Ordinal,
bytes: &[u8],
trace: Option<TraceContext>,
) -> Result<(), RaiseError> {
self.handles.sink.raise(iface, ord, bytes, trace)
}
}
impl<E: Encoding> Caller for Loopback<E> {
fn command(
&mut self,
iface: InterfaceNo,
ord: Ordinal,
args: &[u8],
trace: Option<TraceContext>,
) -> Result<Correlation, SendError> {
self.handles.caller.command(iface, ord, args, trace)
}
fn query(
&mut self,
iface: InterfaceNo,
ord: Ordinal,
args: &[u8],
trace: Option<TraceContext>,
) -> Result<Correlation, SendError> {
self.handles.caller.query(iface, ord, args, trace)
}
fn ack(&mut self, c: Correlation) -> Option<Result<(), CallError>> {
self.handles.caller.ack(c)
}
fn reply(
&mut self,
c: Correlation,
out: &mut [u8],
) -> Result<Option<Result<usize, CallError>>, ReadError> {
self.handles.caller.reply(c, out)
}
fn forget(&mut self, c: Correlation) {
self.handles.caller.forget(c);
}
}
impl<E: Encoding> Handler for Loopback<E> {
fn serve(&mut self, iface: InterfaceNo, ords: &[Ordinal]) -> Result<(), ServeError> {
self.handles.handler.serve(iface, ords)
}
fn next_claim(&mut self, out: &mut [u8]) -> Result<Option<Claim>, ReadError> {
self.handles.handler.next_claim(out)
}
fn settle(
&mut self,
claim: ClaimId,
outcome: Result<&[u8], CallError>,
) -> Result<(), SettleError> {
self.handles.handler.settle(claim, outcome)
}
}
impl<E: Encoding> Wakeable for Loopback<E> {
fn wake_on(&self, what: Interest, waker: &Waker) {
match what {
Interest::Outcome(_) | Interest::Slot => self.handles.caller.wake_on(what, waker),
Interest::Event(_) => self.handles.source.wake_on(what, waker),
Interest::Claim(_) => self.handles.handler.wake_on(what, waker),
}
}
}
const _: () = {
const fn assert_sync<T: Sync>() {}
const fn assert_send<T: Send>() {}
assert_sync::<ReaderHandle>();
assert_send::<ReaderHandle>();
assert_send::<WriterHandle>();
assert_send::<SourceHandle>();
assert_send::<SinkHandle>();
assert_send::<CallerHandle>();
assert_send::<HandlerHandle>();
assert_send::<Loopback>();
assert_send::<Loopback<ridl_rt::encoding::Proto3>>();
};