mod inline_bytes;
mod inline_json;
mod inline_nchar;
mod inline_str;
mod inline_read;
mod inline_write;
use std::{
collections::BTreeMap,
io::{Read, Write},
};
use tokio::io::{AsyncRead, AsyncWrite};
pub use inline_bytes::InlineBytes;
pub use inline_json::InlineJson;
pub use inline_nchar::InlineNChar;
pub use inline_str::InlineStr;
pub use inline_read::AsyncInlinableRead;
pub use inline_write::AsyncInlinableWrite;
use crate::{RawError, RawResult};
#[derive(Debug)]
pub struct Edition {
pub edition: String,
pub expired: bool,
}
impl Edition {
pub fn new(edition: impl Into<String>, expired: bool) -> Self {
Self {
edition: edition.into(),
expired,
}
}
pub fn is_enterprise_edition(&self) -> bool {
match (self.edition.as_str(), self.expired) {
("cloud", _) => true,
("official" | "trial", false) => true,
_ => false,
}
}
pub fn assert_enterprise_edition(&self) -> RawResult<()> {
match (self.edition.as_str(), self.expired) {
("cloud", _) => Ok(()),
("official" | "trial", false) => Ok(()),
("official" | "trial", true) => {
Err(RawError::from_string("your edition is expired".to_string()))
}
_ => Err(RawError::from_string(format!(
"edition: {}; expired: {}",
self.edition, self.expired
))),
}
}
}
pub trait InlinableWrite: Write {
#[inline]
fn write_len_with_width<const N: usize>(&mut self, len: usize) -> std::io::Result<usize> {
self.write_all(&len.to_le_bytes()[0..N])?;
Ok(N)
}
#[inline]
fn write_u8_le(&mut self, value: u8) -> std::io::Result<usize> {
self.write(&[value])
}
#[inline]
fn write_u16_le(&mut self, value: u16) -> std::io::Result<usize> {
self.write(&value.to_le_bytes())
}
#[inline]
fn write_u32_le(&mut self, value: u32) -> std::io::Result<usize> {
self.write(&value.to_le_bytes())
}
#[inline]
fn write_i64_le(&mut self, value: i64) -> std::io::Result<usize> {
self.write(&value.to_le_bytes())
}
#[inline]
fn write_u64_le(&mut self, value: u64) -> std::io::Result<usize> {
self.write(&value.to_le_bytes())
}
#[inline]
fn write_u128_le(&mut self, value: u128) -> std::io::Result<usize> {
self.write(&value.to_le_bytes())
}
#[inline]
fn write_inlined_bytes<const N: usize>(&mut self, bytes: &[u8]) -> std::io::Result<usize> {
debug_assert_eq!(bytes.len() >> (N * 8), 0);
let l = self.write(&bytes.len().to_le_bytes()[0..N])?;
self.write_all(bytes)?;
Ok(l + bytes.len())
}
#[inline]
fn write_inlined_str<const N: usize>(&mut self, s: &str) -> std::io::Result<usize> {
self.write_inlined_bytes::<N>(s.as_bytes())
}
#[inline]
fn write_inlinable<T: Inlinable>(&mut self, value: &T) -> std::io::Result<usize>
where
Self: Sized,
{
value.write_inlined(self)
}
}
impl<T> InlinableWrite for T where T: Write {}
impl<T> InlinableRead for T where T: Read {}
macro_rules! _impl_read_exact {
($ty: ty, $N: literal) => {
paste::paste! {
fn [<read_ $ty>](&mut self) -> std::io::Result<$ty> {
let mut bytes = [0; $N];
self.read_exact(&mut bytes)?;
Ok($ty::from_le_bytes(bytes))
}
}
};
}
pub trait InlinableRead: Read {
#[inline]
fn read_len_with_width<const N: usize>(&mut self) -> std::io::Result<usize> {
let mut bytes: [u8; N] = [0; N];
self.read_exact(&mut bytes)?;
let len = match N {
1 => bytes[0] as usize,
2 => unsafe { *std::mem::transmute::<*const u8, *const u16>(bytes.as_ptr()) as usize },
4 => unsafe { *std::mem::transmute::<*const u8, *const u32>(bytes.as_ptr()) as usize },
8 => unsafe { *std::mem::transmute::<*const u8, *const u64>(bytes.as_ptr()) as usize },
_ => unreachable!(),
};
Ok(len)
}
fn read_f32(&mut self) -> std::io::Result<f32> {
let mut bytes = [0; 4];
self.read_exact(&mut bytes)?;
Ok(f32::from_le_bytes(bytes))
}
fn read_f64(&mut self) -> std::io::Result<f64> {
let mut bytes = [0; 8];
self.read_exact(&mut bytes)?;
Ok(f64::from_le_bytes(bytes))
}
fn read_u8(&mut self) -> std::io::Result<u8> {
let mut bytes = [0; 1];
self.read_exact(&mut bytes)?;
Ok(u8::from_le_bytes(bytes))
}
fn read_u16(&mut self) -> std::io::Result<u16> {
let mut bytes = [0; 2];
self.read_exact(&mut bytes)?;
Ok(u16::from_le_bytes(bytes))
}
fn read_u32(&mut self) -> std::io::Result<u32> {
let mut bytes = [0; 4];
self.read_exact(&mut bytes)?;
Ok(u32::from_le_bytes(bytes))
}
fn read_u64(&mut self) -> std::io::Result<u64> {
let mut bytes = [0; 8];
self.read_exact(&mut bytes)?;
Ok(u64::from_le_bytes(bytes))
}
fn read_u128(&mut self) -> std::io::Result<u128> {
let mut bytes = [0; 16];
self.read_exact(&mut bytes)?;
Ok(u128::from_le_bytes(bytes))
}
#[inline]
fn read_len_with_data<const N: usize>(&mut self) -> std::io::Result<Vec<u8>> {
let len = self.read_len_with_width::<N>()?;
let mut buf = Vec::with_capacity(len);
buf.extend(&(len as u64).to_le_bytes()[0..N]);
buf.resize(len, 0);
self.read_exact(&mut buf[N..])?;
Ok(buf)
}
#[inline]
fn read_inlined_bytes<const N: usize>(&mut self) -> std::io::Result<Vec<u8>> {
let len = self.read_len_with_width::<N>()?;
let mut buf = vec![0; len];
self.read_exact(&mut buf)?;
Ok(buf)
}
#[inline]
fn read_inlined_str<const N: usize>(&mut self) -> std::io::Result<String> {
self.read_inlined_bytes::<N>().and_then(|vec| {
String::from_utf8(vec)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))
})
}
#[inline]
fn read_inlinable<T: Inlinable>(&mut self) -> std::io::Result<T>
where
Self: Sized,
{
T::read_inlined(self)
}
}
pub struct InlineOpts {
pub opts: BTreeMap<String, String>,
}
pub trait Inlinable {
fn read_inlined<R: Read>(reader: &mut R) -> std::io::Result<Self>
where
Self: Sized;
fn read_optional_inlined<R: Read>(reader: &mut R) -> std::io::Result<Option<Self>>
where
Self: Sized,
{
Self::read_inlined(reader).map(Some)
}
fn write_inlined<W: Write>(&self, wtr: &mut W) -> std::io::Result<usize>;
fn write_inlined_with<W: Write>(
&self,
wtr: &mut W,
_opts: InlineOpts,
) -> std::io::Result<usize> {
self.write_inlined(wtr)
}
#[inline]
fn inlined(&self) -> Vec<u8> {
let mut buf = Vec::new();
self.write_inlined(&mut buf)
.expect("write to vec should always be success");
buf
}
#[inline]
fn printable_inlined(&self) -> String {
self.inlined().escape_ascii().to_string()
}
}
#[async_trait::async_trait]
pub trait AsyncInlinable {
async fn read_inlined<R: AsyncRead + Send + Unpin>(reader: &mut R) -> std::io::Result<Self>
where
Self: Sized;
async fn read_optional_inlined<R: AsyncRead + Send + Unpin>(
reader: &mut R,
) -> std::io::Result<Option<Self>>
where
Self: Sized,
{
Self::read_inlined(reader).await.map(Some)
}
async fn write_inlined<W: AsyncWrite + Send + Unpin>(
&self,
wtr: &mut W,
) -> std::io::Result<usize>;
async fn write_inlined_with<W: AsyncWrite + Send + Unpin>(
&self,
wtr: &mut W,
_opts: InlineOpts,
) -> std::io::Result<usize> {
self.write_inlined(wtr).await
}
#[inline]
async fn inlined(&self) -> Vec<u8> {
let mut buf = Vec::new();
self.write_inlined(&mut buf)
.await
.expect("write to vec should always be success");
buf
}
#[inline]
async fn printable_inlined(&self) -> String {
self.inlined().await.escape_ascii().to_string()
}
}
#[test]
fn inlined_bytes() -> std::io::Result<()> {
let s = "abcd";
let mut vec: Vec<u8> = Vec::new();
let bytes = InlinableWrite::write_inlined_bytes::<1>(&mut vec, s.as_bytes())?;
assert_eq!(bytes, 5);
assert_eq!(&vec, b"\x04abcd");
let r = InlinableRead::read_inlined_str::<1>(&mut vec.as_slice())?;
assert_eq!(r, "abcd");
Ok(())
}