use crate::error::Error;
use crate::Element;
use crate::Query;
use crate::RespCode;
use crate::SkyResult;
use core::convert::TryInto;
use core::ops::Deref;
use core::ops::DerefMut;
const BAD_ELEMENT: &str = "Bad element type for parsing into custom type";
const HAS_NULL_ELEMENTS: &str = "Array has null elements";
pub trait IntoSkyhashBytes: Send + Sync {
fn as_bytes(&self) -> Vec<u8>;
}
macro_rules! impl_skyhash_bytes {
($($ty:ty),*) => {
$(
impl IntoSkyhashBytes for $ty {
fn as_bytes(&self) -> Vec<u8> {
self.to_string().into_bytes()
}
}
)*
};
}
impl_skyhash_bytes!(String, &str, &String, str);
pub trait IntoSkyhashAction: Send + Sync {
fn push_into_query(&self, data: &mut Query);
fn incr_len_by(&self) -> usize;
}
impl<T> IntoSkyhashAction for T
where
T: IntoSkyhashBytes,
{
fn push_into_query(&self, q: &mut Query) {
q._push_arg(self.as_bytes());
}
fn incr_len_by(&self) -> usize {
1
}
}
impl<T> IntoSkyhashAction for Vec<T>
where
T: IntoSkyhashBytes,
{
fn push_into_query(&self, data: &mut Query) {
self.iter().for_each(|elem| elem.push_into_query(data));
}
fn incr_len_by(&self) -> usize {
self.len()
}
}
impl<T> IntoSkyhashAction for &Vec<T>
where
T: IntoSkyhashBytes,
{
fn push_into_query(&self, data: &mut Query) {
self.iter().for_each(|elem| elem.push_into_query(data));
}
fn incr_len_by(&self) -> usize {
self.len()
}
}
impl<T> IntoSkyhashAction for &[T]
where
T: IntoSkyhashBytes,
{
fn push_into_query(&self, data: &mut Query) {
self.iter().for_each(|elem| elem.push_into_query(data));
}
fn incr_len_by(&self) -> usize {
self.len()
}
}
#[cfg(feature = "const-gen")]
impl<T: IntoSkyhashBytes, const N: usize> IntoSkyhashAction for [T; N] {
fn push_into_query(&self, data: &mut Query) {
self.iter().for_each(|elem| elem.push_into_query(data));
}
fn incr_len_by(&self) -> usize {
self.len()
}
}
#[cfg(feature = "const-gen")]
impl<T: IntoSkyhashBytes, const N: usize> IntoSkyhashAction for &'static [T; N] {
fn push_into_query(&self, data: &mut Query) {
self.iter().for_each(|elem| elem.push_into_query(data));
}
fn incr_len_by(&self) -> usize {
N
}
}
#[non_exhaustive]
pub enum SnapshotResult {
Okay,
Disabled,
Busy,
}
pub trait GetIterator<T: IntoSkyhashBytes>: IntoSkyhashAction {
fn get_iter(&self) -> std::slice::Iter<T>;
}
#[cfg(feature = "const-gen")]
impl<T: IntoSkyhashBytes, const N: usize> GetIterator<T> for [T; N] {
fn get_iter(&self) -> std::slice::Iter<'_, T> {
self.iter()
}
}
#[cfg(feature = "const-gen")]
impl<T: IntoSkyhashBytes, const N: usize> GetIterator<T> for &'static [T; N] {
fn get_iter(&self) -> std::slice::Iter<'_, T> {
self.iter()
}
}
impl<'a, T: IntoSkyhashBytes> GetIterator<T> for &'a [T] {
fn get_iter(&self) -> std::slice::Iter<'_, T> {
self.iter()
}
}
impl<T: IntoSkyhashBytes> GetIterator<T> for Vec<T> {
fn get_iter(&self) -> std::slice::Iter<'_, T> {
self.iter()
}
}
#[derive(Debug, PartialEq)]
#[non_exhaustive]
pub enum Array {
Bin(Vec<Option<Vec<u8>>>),
NonNullBin(Vec<Vec<u8>>),
Str(Vec<Option<String>>),
NonNullStr(Vec<String>),
Flat(Vec<FlatElement>),
Recursive(Vec<Element>),
}
#[derive(Debug, PartialEq)]
#[non_exhaustive]
pub enum FlatElement {
String(String),
Binstr(Vec<u8>),
RespCode(RespCode),
UnsignedInt(u64),
}
#[derive(Debug, PartialEq)]
pub struct RawString(Vec<u8>);
impl Default for RawString {
fn default() -> Self {
Self::new()
}
}
impl RawString {
pub fn with_capacity(cap: usize) -> Self {
Self(Vec::with_capacity(cap))
}
pub fn new() -> Self {
Self(Vec::new())
}
}
impl Deref for RawString {
type Target = Vec<u8>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for RawString {
fn deref_mut(&mut self) -> &mut Vec<u8> {
&mut self.0
}
}
impl From<Vec<u8>> for RawString {
fn from(oth: Vec<u8>) -> Self {
Self(oth)
}
}
impl PartialEq<Vec<u8>> for RawString {
fn eq(&self, oth: &Vec<u8>) -> bool {
self.0.eq(oth)
}
}
impl Eq for RawString {}
impl IntoSkyhashBytes for RawString {
fn as_bytes(&self) -> Vec<u8> {
self.0.to_owned()
}
}
impl<'a> IntoSkyhashBytes for &'a RawString {
fn as_bytes(&self) -> Vec<u8> {
self.0.to_owned()
}
}
pub trait FromSkyhashBytes: Sized {
fn from_element(element: Element) -> SkyResult<Self>;
}
macro_rules! impl_from_skyhash {
($($ty:ty),* $(,)?) => {
$(impl FromSkyhashBytes for $ty {
fn from_element(element: Element) -> SkyResult<$ty> {
let ret = match element {
Element::Binstr(bstr) => String::from_utf8_lossy(&bstr).parse::<$ty>()?,
Element::String(st) => st.parse::<$ty>()?,
Element::UnsignedInt(int) => int.try_into()?,
_ => return Err(Error::ParseError(BAD_ELEMENT.to_owned())),
};
Ok(ret)
}
})*
};
}
impl_from_skyhash!(u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize);
impl FromSkyhashBytes for String {
fn from_element(element: Element) -> SkyResult<String> {
let e = match element {
Element::Binstr(bstr) => std::string::String::from_utf8(bstr)?,
Element::String(st) => st,
Element::UnsignedInt(int) => int.to_string(),
_ => return Err(Error::ParseError(BAD_ELEMENT.to_owned())),
};
Ok(e)
}
}
impl FromSkyhashBytes for Vec<String> {
fn from_element(element: Element) -> SkyResult<Self> {
let e = match element {
Element::Array(Array::Bin(binarr)) => {
let mut new_arr = Vec::with_capacity(binarr.len());
for item in binarr {
if let Some(item) = item {
new_arr.push(String::from_utf8(item)?);
} else {
return Err(Error::ParseError(HAS_NULL_ELEMENTS.to_owned()));
}
}
new_arr
}
Element::Array(Array::Str(strarr)) => {
let mut new_arr = Vec::with_capacity(strarr.len());
for item in strarr {
if let Some(item) = item {
new_arr.push(item);
} else {
return Err(Error::ParseError(HAS_NULL_ELEMENTS.to_owned()));
}
}
new_arr
}
Element::Array(Array::NonNullStr(strarr)) => strarr,
Element::Array(Array::NonNullBin(binarr)) => {
let mut ret = Vec::with_capacity(binarr.len());
for item in binarr {
ret.push(String::from_utf8(item)?);
}
ret
}
_ => return Err(Error::ParseError(BAD_ELEMENT.to_owned())),
};
Ok(e)
}
}
impl FromSkyhashBytes for Vec<Vec<u8>> {
fn from_element(e: Element) -> SkyResult<Self> {
let e = match e {
Element::Array(Array::Bin(brr)) => {
let mut newarr = Vec::with_capacity(brr.len());
for item in brr {
if let Some(item) = item {
newarr.push(item);
} else {
return Err(Error::ParseError(HAS_NULL_ELEMENTS.to_owned()));
}
}
newarr
}
Element::Array(Array::Str(srr)) => {
let mut newarr = Vec::with_capacity(srr.len());
for item in srr {
if let Some(item) = item {
newarr.push(item.into_bytes());
} else {
return Err(Error::ParseError(HAS_NULL_ELEMENTS.to_owned()));
}
}
newarr
}
Element::Array(Array::NonNullStr(strarr)) => {
strarr.into_iter().map(|v| v.into_bytes()).collect()
}
Element::Array(Array::NonNullBin(brr)) => brr,
_ => return Err(Error::ParseError(BAD_ELEMENT.to_owned())),
};
Ok(e)
}
}
impl FromSkyhashBytes for Element {
fn from_element(e: Element) -> SkyResult<Element> {
Ok(e)
}
}
macro_rules! impl_fsb {
($($for:ty: $eval:pat => $ret:expr),* $(,)?) => {
$(impl FromSkyhashBytes for $for {
fn from_element(element: Element) -> SkyResult<Self> {
match element {
$eval => Ok($ret),
x => Err(Error::ParseError(format!(
"expected `{}`, found {:?}",
stringify!($for),
x
))),
}
}
})*
};
}
impl_fsb!(
RespCode: Element::RespCode(rc) => rc,
Array: Element::Array(ar) => ar,
);
#[test]
fn test_arr_from_str_to_vecstr() {
let arr = Element::Array(Array::Str(vec![
Some("hello1".to_owned()),
Some("world1".to_owned()),
Some("hello2".to_owned()),
Some("world2".to_owned()),
]));
let arr: Vec<String> = arr.try_element_into().unwrap();
assert_eq!(
arr,
vec![
"hello1".to_owned(),
"world1".to_owned(),
"hello2".to_owned(),
"world2".to_owned()
]
);
}
#[test]
fn test_arr_from_str_with_null_to_vecstr() {
let arr = Element::Array(Array::Str(vec![
Some("hello1".to_owned()),
Some("world1".to_owned()),
None,
Some("world2".to_owned()),
]));
assert_eq!(
arr.try_element_into::<Vec<String>>().unwrap_err(),
Error::ParseError(HAS_NULL_ELEMENTS.to_string())
)
}