use std::fmt;
use std::marker::PhantomData;
use crate::error::{EncodeError, ProviderError};
use crate::streaming::UnknownPayload;
use crate::wire::{
Capabilities, Decoder, Descriptor, Flow, Free, Mode, Operation, Out, Wire, WireEvent,
};
pub struct Local<Op> {
name: String,
id: Option<String>,
capabilities: Capabilities,
op: PhantomData<fn() -> Op>,
}
pub enum Step<Op: Operation> {
Event(Op::Event),
Unknown(UnknownPayload),
End(Op::End),
}
impl<Op: Operation<Emit = Free>> Local<Op> {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
id: None,
capabilities: Capabilities::default(),
op: PhantomData,
}
}
pub fn with_capabilities(mut self, capabilities: Capabilities) -> Self {
self.capabilities = capabilities;
self
}
pub fn with_id(mut self, id: impl Into<String>) -> Self {
self.id = Some(id.into());
self
}
}
impl<Op> Clone for Local<Op> {
fn clone(&self) -> Self {
Self {
name: self.name.clone(),
id: self.id.clone(),
capabilities: self.capabilities,
op: PhantomData,
}
}
}
impl<Op> fmt::Debug for Local<Op> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Local")
.field("name", &self.name)
.field("id", &self.id)
.field("capabilities", &self.capabilities)
.finish()
}
}
impl<Op: Operation<Emit = Free>> Wire for Local<Op> {
type Op = Op;
type Payload = Op::Request;
type Frame = Step<Op>;
type Decoder<'id> = Steps;
type Reassembler = crate::wire::document::Unreassembled;
fn describe(&self) -> Descriptor<'_> {
Descriptor::new(&self.name)
.model(self.id.as_deref())
.capabilities(self.capabilities)
}
fn encode(&self, request: Op::Request, _mode: Mode) -> Result<Op::Request, EncodeError> {
Ok(request)
}
fn decoder<'id>(&self) -> Self::Decoder<'id> {
Steps
}
}
#[derive(Debug, Default)]
pub struct Steps;
impl<'id, Op: Operation<Emit = Free>> Decoder<'id, Op, Step<Op>> for Steps {
type Event = Step<Op>;
fn classify(&self, step: Step<Op>) -> WireEvent<Step<Op>> {
WireEvent::Known(step)
}
fn decode(&mut self, step: Step<Op>, mut out: Out<'id, Op>) -> Result<Flow, ProviderError> {
Ok(match step {
Step::Event(event) => {
out.event(event);
Flow::More
}
Step::Unknown(payload) => {
out.unknown(payload);
Flow::More
}
Step::End(end) => out.end(end),
})
}
}