Skip to main content

StdioSource

Struct StdioSource 

Source
pub struct StdioSource<R> { /* private fields */ }
Expand description

A FrameSource over any AsyncRead.

§Examples

A frame split across two reads is reassembled, because the partial Ok(None) from the decoder is a reason to read again rather than an answer:

use std::pin::Pin;
use std::task::{Context, Poll};

use protocol_droid::adapters::primary::stdio::{StdioConfig, StdioError, StdioSource};
use protocol_droid::application::jsonrpc::FrameSource;
use protocol_droid::domain::MaxFrameSize;
use tokio::io::{AsyncRead, ReadBuf};

/// Hands over at most three bytes per read, so a frame cannot arrive whole.
struct Trickle {
    data: Vec<u8>,
    served: usize,
}

impl AsyncRead for Trickle {
    fn poll_read(
        mut self: Pin<&mut Self>,
        _cx: &mut Context<'_>,
        buf: &mut ReadBuf<'_>,
    ) -> Poll<std::io::Result<()>> {
        let end = (self.served + 3).min(self.data.len());
        let Some(chunk) = self.data.get(self.served..end) else {
            return Poll::Ready(Ok(())); // end of stream
        };
        buf.put_slice(chunk);
        self.served = end;
        Poll::Ready(Ok(()))
    }
}

let stream = Trickle { data: b"{\"jsonrpc\":\"2.0\"}\n".to_vec(), served: 0 };
let source = StdioSource::new(stream, StdioConfig::new(MaxFrameSize::new(1024)?));

assert_eq!(source.next_frame().await?, Some(r#"{"jsonrpc":"2.0"}"#.to_owned()));

Implementations§

Source§

impl<R> StdioSource<R>

Source

pub fn new(stream: R, config: StdioConfig) -> Self

Wraps a stream, decoding frames at the configured ceiling.

Source

pub const fn config(&self) -> StdioConfig

The settings this source was built with.

Source

pub const fn limit(&self) -> MaxFrameSize

The ceiling this source refuses frames above.

Source§

impl<R> StdioSource<R>
where R: AsyncRead + Unpin,

Source

pub async fn next_frame(&self) -> Result<Option<String>, SourceError>

Reads the peer’s next frame, waiting for as many reads as that takes.

This is the read loop, and the reason this type exists. Every exit from it is a decision, and the decoder’s None is not one of them.

§Errors

SourceError::Transport when a read fails, which is latched, and SourceError::Framing when the peer’s bytes are not a frame — most often crate::domain::FramingError::FrameTooLarge, or bytes that are not UTF-8.

Ok(None) is the peer closing and only that.

The lock is held for the whole loop, which is the point of holding one: two callers must not interleave a read with the decoder that consumes what it returned. Every exit from the loop is still holding it, so the guard has no earlier last use to be tightened to.

Trait Implementations§

Source§

impl<R: Debug> Debug for StdioSource<R>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<R> FrameSource for StdioSource<R>
where R: AsyncRead + Unpin + Send,

Source§

fn next_frame( &self, ) -> impl Future<Output = Result<Option<String>, SourceError>> + Send

Waits for the peer’s next frame.

The port’s Ok(None) is the peer closing, so this never returns the decoder’s “no terminator yet” — see the module docs for why the two Nones are opposites and what inverting them looks like from the outside.

A framing error is not latched: the decoder refused the bytes and kept its own buffer, so the next call is refused again by the same check rather than by a flag, and the stream stays open for the caller to shut down.

§Errors

As StdioSource::next_frame.

Auto Trait Implementations§

§

impl<R> !Freeze for StdioSource<R>

§

impl<R> !RefUnwindSafe for StdioSource<R>

§

impl<R> Send for StdioSource<R>
where Mutex<Inner<R>>: Send,

§

impl<R> Sync for StdioSource<R>
where Mutex<Inner<R>>: Sync,

§

impl<R> Unpin for StdioSource<R>
where Mutex<Inner<R>>: Unpin,

§

impl<R> UnsafeUnpin for StdioSource<R>
where Mutex<Inner<R>>: UnsafeUnpin,

§

impl<R> UnwindSafe for StdioSource<R>
where Mutex<Inner<R>>: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> DynFrameSource for T
where T: FrameSource + Send + Sync,

Source§

fn next_frame<'a>( &'a self, ) -> Pin<Box<dyn Future<Output = Result<Option<String>, SourceError>> + Send + 'a>>

Waits for the peer’s next frame. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more