#![cfg_attr(
all(doc, all(doc, feature = "document-features")),
doc = ::document_features::document_features!()
)]
#![cfg_attr(all(doc, feature = "document-features"), feature(doc_cfg))]
#![deny(missing_docs, rust_2018_idioms, unsafe_code)]
use bstr::BStr;
#[cfg(feature = "async-io")]
pub mod async_io {
pub mod encode;
mod read;
pub use read::StreamingPeekableIter;
mod sidebands;
pub use sidebands::WithSidebands;
mod write;
pub use write::Writer;
}
#[cfg(feature = "blocking-io")]
pub mod blocking_io {
pub mod encode;
mod read;
pub use read::StreamingPeekableIter;
mod sidebands;
pub use sidebands::WithSidebands;
mod write;
pub use write::Writer;
}
pub mod read;
const U16_HEX_BYTES: usize = 4;
const MAX_DATA_LEN: usize = 65516;
const MAX_LINE_LEN: usize = MAX_DATA_LEN + U16_HEX_BYTES;
const FLUSH_LINE: &[u8] = b"0000";
const DELIMITER_LINE: &[u8] = b"0001";
const RESPONSE_END_LINE: &[u8] = b"0002";
const ERR_PREFIX: &[u8] = b"ERR ";
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Channel {
Data = 1,
Progress = 2,
Error = 3,
}
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum PacketLineRef<'a> {
Data(&'a [u8]),
Flush,
Delimiter,
ResponseEnd,
}
impl<'a> PacketLineRef<'a> {
pub fn as_slice(&self) -> Option<&'a [u8]> {
match self {
PacketLineRef::Data(d) => Some(d),
PacketLineRef::Flush | PacketLineRef::Delimiter | PacketLineRef::ResponseEnd => None,
}
}
pub fn as_bstr(&self) -> Option<&'a BStr> {
self.as_slice().map(Into::into)
}
pub fn as_error(&self) -> Option<ErrorRef<'a>> {
self.as_slice().map(ErrorRef)
}
pub fn check_error(&self) -> Option<ErrorRef<'a>> {
self.as_slice().and_then(|data| {
if data.len() >= ERR_PREFIX.len() && &data[..ERR_PREFIX.len()] == ERR_PREFIX {
Some(ErrorRef(&data[ERR_PREFIX.len()..]))
} else {
None
}
})
}
pub fn as_text(&self) -> Option<TextRef<'a>> {
self.as_slice().map(Into::into)
}
pub fn as_band(&self, kind: Channel) -> Option<BandRef<'a>> {
self.as_slice().map(|d| match kind {
Channel::Data => BandRef::Data(d),
Channel::Progress => BandRef::Progress(d),
Channel::Error => BandRef::Error(d),
})
}
pub fn decode_band(&self) -> Result<BandRef<'a>, decode::band::Error> {
let d = self.as_slice().ok_or(decode::band::Error::NonDataLine)?;
Ok(match d[0] {
1 => BandRef::Data(&d[1..]),
2 => BandRef::Progress(&d[1..]),
3 => BandRef::Error(&d[1..]),
band => return Err(decode::band::Error::InvalidSideBand { band_id: band }),
})
}
}
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ErrorRef<'a>(pub &'a [u8]);
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TextRef<'a>(pub &'a [u8]);
impl<'a> TextRef<'a> {
pub fn as_slice(&self) -> &'a [u8] {
self.0
}
pub fn as_bstr(&self) -> &'a BStr {
self.0.into()
}
}
impl<'a> From<&'a [u8]> for TextRef<'a> {
fn from(d: &'a [u8]) -> Self {
let d = if d[d.len() - 1] == b'\n' { &d[..d.len() - 1] } else { d };
TextRef(d)
}
}
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum BandRef<'a> {
Data(&'a [u8]),
Progress(&'a [u8]),
Error(&'a [u8]),
}
pub mod decode;
#[doc(inline)]
pub use decode::all_at_once as decode;
pub mod encode;