pub struct Diagnostics<W> { /* private fields */ }Expand description
A writer bound to one stream, safe to share.
Generic over the stream so a test can hand it a buffer and read the bytes
back. In production that buffer is stderr, and
Diagnostics::stderr is the only constructor that says so.
§Examples
use protocol_droid::adapters::primary::stdio::Diagnostics;
// The real channel: process stderr, and nothing else.
let diagnostics = Diagnostics::stderr();
diagnostics.write_all(b"listening on stdio\n").await?;Implementations§
Source§impl Diagnostics<Stderr>
impl Diagnostics<Stderr>
Source§impl<W> Diagnostics<W>
impl<W> Diagnostics<W>
Source§impl<W> Diagnostics<W>where
W: AsyncWrite + Unpin,
impl<W> Diagnostics<W>where
W: AsyncWrite + Unpin,
Sourcepub async fn write_all(&self, bytes: &[u8]) -> Result<(), StdioError>
pub async fn write_all(&self, bytes: &[u8]) -> Result<(), StdioError>
Writes a diagnostic line, holding the lock for the whole write.
The lock spans the write rather than the frame boundary because a diagnostic interleaved with another diagnostic is a corrupted log, and a corrupted log is the failure mode that makes people turn logging off.
§Errors
StdioError::Transport when the underlying stream refuses the bytes.
A diagnostic that cannot be written is never worth failing a request
over, so callers that treat it as best-effort can discard this.
Sourcepub async fn writer(&self) -> DiagnosticsWriter<'_, W>
pub async fn writer(&self) -> DiagnosticsWriter<'_, W>
Borrows the channel as a plain AsyncWrite, for a caller that already
holds an AsyncWrite and would otherwise need a wrapper.
The borrow is the point, and it is why this is not an AsyncWrite impl
on Diagnostics itself. The AsyncWrite methods take &mut self, so
implementing the trait on the shared type would mean the channel could
only ever be written by one task at a time and could not be shared at
all — and a diagnostics channel that cannot be shared is not one. The
returned guard holds the lock for as long as the caller keeps it, which
makes write_all the same operation spelled
differently rather than a different guarantee.
A guard is the borrow check made visible: it will not compile if the
caller tries to reach the channel a second time while holding it, which
is the mistake a shared AsyncWrite implementation would have hidden
behind a lock.