#![cfg_attr(docsrs, feature(doc_cfg))]
#[macro_use]
mod util;
pub mod actions;
mod deserializer;
mod respcode;
pub mod types;
use crate::types::GetIterator;
pub use deserializer::Element;
pub use respcode::RespCode;
pub(crate) use std::io::Result as IoResult;
use types::IntoSkyhashAction;
use types::IntoSkyhashBytes;
cfg_async!(
pub mod aio;
pub use aio::Connection as AsyncConnection;
use tokio::io::AsyncWriteExt;
);
cfg_sync!(
pub mod sync;
pub use sync::Connection;
);
#[macro_export]
macro_rules! query {
($($arg:expr),+) => {
skytable::Query::new()$(.arg($arg))*
};
}
#[derive(Debug, PartialEq)]
pub struct Query {
size_count: usize,
data: Vec<u8>,
}
impl<T> From<T> for Query
where
T: IntoSkyhashAction,
{
fn from(action: T) -> Self {
Query::new().arg(action)
}
}
impl Default for Query {
fn default() -> Self {
Query {
size_count: 0,
data: Vec::new(),
}
}
}
impl Query {
pub fn new() -> Self {
Query::default()
}
pub fn arg(mut self, arg: impl IntoSkyhashAction) -> Self {
arg.push_into_query(&mut self);
self
}
pub(in crate) fn _push_arg(&mut self, arg: impl IntoSkyhashBytes) {
let arg = arg.as_string();
if arg.is_empty() {
panic!("Argument cannot be empty")
}
self.data.push(b'+');
let bytes_in_next_line = arg.len().to_string().into_bytes();
self.data.extend(bytes_in_next_line);
self.data.push(b'\n');
self.data.extend(arg.into_bytes());
self.data.push(b'\n'); self.size_count += 1;
}
pub fn push(&mut self, arg: impl IntoSkyhashAction) {
arg.push_into_query(self);
}
pub(in crate) fn _push_alt_iter<T, U>(
mut self,
v1: impl GetIterator<T>,
v2: impl GetIterator<U>,
) -> Query
where
T: IntoSkyhashBytes,
U: IntoSkyhashBytes,
{
v1.get_iter().zip(v2.get_iter()).for_each(|(a, b)| {
self.push(a.as_string());
self.push(b.as_string());
});
self
}
pub(crate) fn __len(&self) -> usize {
self.size_count
}
fn get_holding_buffer(&self) -> &[u8] {
&self.data
}
cfg_async!(
async fn write_query_to<T>(&self, stream: &mut T) -> IoResult<()>
where
T: tokio::io::AsyncWrite + Unpin,
{
stream.write_all(b"*1\n").await?;
let number_of_items_in_datagroup = self.__len().to_string().into_bytes();
stream.write_all(&[b'_']).await?;
stream.write_all(&number_of_items_in_datagroup).await?;
stream.write_all(&[b'\n']).await?;
stream.write_all(self.get_holding_buffer()).await?;
stream.flush().await?;
Ok(())
}
);
cfg_sync!(
fn write_query_to_sync<T>(&self, stream: &mut T) -> IoResult<()>
where
T: std::io::Write,
{
stream.write_all(b"*1\n")?;
let number_of_items_in_datagroup = self.__len().to_string().into_bytes();
stream.write_all(&[b'_'])?;
stream.write_all(&number_of_items_in_datagroup)?;
stream.write_all(&[b'\n'])?;
stream.write_all(self.get_holding_buffer())?;
stream.flush()?;
Ok(())
}
);
cfg_dbg!(
pub fn into_raw_query(self) -> Vec<u8> {
let mut v = Vec::with_capacity(self.data.len());
v.extend(b"*1\n_");
v.extend(self.__len().to_string().into_bytes());
v.extend(b"\n");
v.extend(self.get_holding_buffer());
v
}
pub fn array_packet_size_hint(element_lengths: impl AsRef<[usize]>) -> usize {
let element_lengths = element_lengths.as_ref();
let mut len = 0_usize;
len += 4;
let dig_count = |dig| -> usize {
let dig_count = (dig as f32).log(10.0_f32).floor() + 1_f32;
dig_count as usize
};
len += dig_count(element_lengths.len());
len += 1;
element_lengths.iter().for_each(|elem| {
len += 1;
len += dig_count(*elem);
len += 1;
len += elem;
len += 1;
});
len
}
);
}
#[derive(Debug, PartialEq)]
#[non_exhaustive]
pub enum Response {
InvalidResponse,
Item(Element),
ParseError,
UnsupportedDataType,
}
cfg_dbg!(
#[test]
fn my_query() {
let q = vec!["set", "x", "100"];
let ma_query_len = Query::from(&q).into_raw_query().len();
let q_len =
Query::array_packet_size_hint(q.iter().map(|v| v.len()).collect::<Vec<usize>>());
assert_eq!(ma_query_len, q_len);
}
);
pub mod error {
cfg_ssl_any!(
use std::fmt;
pub enum SslError {
IoError(std::io::Error),
SslError(openssl::ssl::Error),
}
impl From<openssl::ssl::Error> for SslError {
fn from(e: openssl::ssl::Error) -> Self {
Self::SslError(e)
}
}
impl From<std::io::Error> for SslError {
fn from(e: std::io::Error) -> Self {
Self::IoError(e)
}
}
impl From<openssl::error::ErrorStack> for SslError {
fn from(e: openssl::error::ErrorStack) -> Self {
Self::SslError(e.into())
}
}
impl fmt::Display for SslError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
Self::IoError(e) => write!(f, "{}", e),
Self::SslError(e) => write!(f, "{}", e),
}
}
}
);
}