mod element;
pub mod hca;
mod pack;
mod subspace;
mod versionstamp;
use std::borrow::Cow;
use std::fmt::{self, Display};
use std::io;
use std::ops::Deref;
use std::result;
#[cfg(feature = "uuid")]
pub use uuid::Uuid;
pub use element::Element;
pub use pack::{TuplePack, TupleUnpack, VersionstampOffset};
pub use subspace::Subspace;
pub use versionstamp::Versionstamp;
const NIL: u8 = 0x00;
const BYTES: u8 = 0x01;
const STRING: u8 = 0x02;
const NESTED: u8 = 0x05;
const NEGINTSTART: u8 = 0x0b;
const INTZERO: u8 = 0x14;
const POSINTEND: u8 = 0x1d;
const FLOAT: u8 = 0x20;
const DOUBLE: u8 = 0x21;
const FALSE: u8 = 0x26;
const TRUE: u8 = 0x27;
#[cfg(feature = "uuid")]
const UUID: u8 = 0x30;
const VERSIONSTAMP: u8 = 0x33;
const ESCAPE: u8 = 0xff;
#[derive(Copy, Clone)]
pub struct TupleDepth(usize);
impl TupleDepth {
    fn new() -> Self {
        TupleDepth(0)
    }
    
    pub fn increment(self) -> Self {
        TupleDepth(self.0 + 1)
    }
    
    pub fn depth(self) -> usize {
        self.0
    }
}
#[derive(Debug)]
pub enum PackError {
    Message(Box<str>),
    IoError(io::Error),
    TrailingBytes,
    MissingBytes,
    BadStringFormat,
    BadCode {
        found: u8,
        expected: Option<u8>,
    },
    BadPrefix,
    #[cfg(feature = "uuid")]
    BadUuid,
    UnsupportedIntLength,
}
impl From<io::Error> for PackError {
    fn from(err: io::Error) -> Self {
        PackError::IoError(err)
    }
}
impl Display for PackError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            PackError::Message(s) => s.fmt(f),
            PackError::IoError(err) => err.fmt(f),
            PackError::TrailingBytes => write!(f, "trailing bytes"),
            PackError::MissingBytes => write!(f, "missing bytes"),
            PackError::BadStringFormat => write!(f, "not an utf8 string"),
            PackError::BadCode { found, .. } => write!(f, "bad code, found {}", found),
            PackError::BadPrefix => write!(f, "bad prefix"),
            #[cfg(feature = "uuid")]
            PackError::BadUuid => write!(f, "bad uuid"),
            PackError::UnsupportedIntLength => write!(f, "integer length was to large"),
        }
    }
}
impl std::error::Error for PackError {}
pub type PackResult<T> = result::Result<T, PackError>;
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Bytes<'a>(pub Cow<'a, [u8]>);
impl<'a> fmt::Debug for Bytes<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}
impl<'a> fmt::Display for Bytes<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "b\"")?;
        for &byte in self.0.iter() {
            if byte == b'\\' {
                write!(fmt, r"\\")?;
            } else if byte.is_ascii_alphanumeric() {
                write!(fmt, "{}", byte as char)?;
            } else {
                write!(fmt, "\\x{:02x}", byte)?;
            }
        }
        write!(fmt, "\"")
    }
}
impl<'a> Bytes<'a> {
    pub fn into_owned(self) -> Vec<u8> {
        self.0.into_owned()
    }
}
impl<'a> Deref for Bytes<'a> {
    type Target = [u8];
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
impl<'a> AsRef<[u8]> for Bytes<'a> {
    fn as_ref(&self) -> &[u8] {
        &self.0
    }
}
impl<'a> From<&'a [u8]> for Bytes<'a> {
    fn from(bytes: &'a [u8]) -> Self {
        Self(Cow::Borrowed(bytes))
    }
}
impl From<Vec<u8>> for Bytes<'static> {
    fn from(vec: Vec<u8>) -> Self {
        Self(Cow::Owned(vec))
    }
}
impl<'a> From<&'a str> for Bytes<'a> {
    fn from(s: &'a str) -> Self {
        s.as_bytes().into()
    }
}
impl From<String> for Bytes<'static> {
    fn from(vec: String) -> Self {
        vec.into_bytes().into()
    }
}
pub fn pack<T: TuplePack>(v: &T) -> Vec<u8> {
    v.pack_to_vec()
}
pub fn pack_with_versionstamp<T: TuplePack>(v: &T) -> Vec<u8> {
    v.pack_to_vec_with_versionstamp()
}
pub fn pack_into<T: TuplePack>(v: &T, output: &mut Vec<u8>) {
    v.pack_into_vec(output)
}
pub fn pack_into_with_versionstamp<T: TuplePack>(v: &T, output: &mut Vec<u8>) {
    let offset = v.pack_into_vec_with_versionstamp(output);
    if let VersionstampOffset::MultipleIncomplete = offset {
        panic!("pack_into_with_versionstamp does not allow multiple versionstamps");
    }
}
pub fn unpack<'de, T: TupleUnpack<'de>>(input: &'de [u8]) -> PackResult<T> {
    T::unpack_root(input)
}
#[cfg(test)]
mod tests {
    use super::*;
    const NIL_VAL: Option<()> = None;
    fn test_serde<'de, T>(val: T, buf: &'de [u8])
    where
        T: TuplePack + TupleUnpack<'de> + fmt::Debug + PartialEq,
    {
        assert_eq!(Bytes::from(pack(&val)), Bytes::from(buf));
        assert_eq!(unpack::<'de, T>(buf).unwrap(), val);
    }
    #[test]
    fn test_spec() {
        test_serde(NIL_VAL, &[NIL]);
        test_serde((NIL_VAL,), &[NIL]);
        test_serde(((NIL_VAL,),), &[NESTED, NIL, ESCAPE, NIL]);
        
        test_serde("FÔO\x00bar".to_owned(), b"\x02F\xc3\x94O\x00\xffbar\x00");
        test_serde(
            (("foo\x00bar".to_owned(), NIL_VAL, ()),),
            b"\x05\x02foo\x00\xffbar\x00\x00\xff\x05\x00\x00",
        );
        test_serde(-1, b"\x13\xfe");
        test_serde(-5551212, b"\x11\xabK\x93");
        test_serde(-42f32, b"\x20\x3d\xd7\xff\xff");
    }
    #[test]
    fn test_simple() {
        
        test_serde(false, &[FALSE]);
        test_serde(true, &[TRUE]);
        
        test_serde(0i64, &[INTZERO]);
        test_serde(1i64, &[0x15, 1]);
        test_serde(-1i64, &[0x13, 254]);
        test_serde(100i64, &[21, 100]);
        test_serde(10000i32, &[22, 39, 16]);
        test_serde(-100i16, &[19, 155]);
        test_serde(-10000i64, &[18, 216, 239]);
        test_serde(-1000000i64, &[17, 240, 189, 191]);
        
        test_serde(255u16, &[0x15, 255]);
        test_serde(256i32, &[0x16, 1, 0]);
        test_serde(-255i16, &[0x13, 0]);
        test_serde(-256i64, &[0x12, 254, 255]);
        
        test_serde(
            Versionstamp::complete(b"\xaa\xbb\xcc\xdd\xee\xff\x00\x01\x02\x03".clone(), 0),
            b"\x33\xaa\xbb\xcc\xdd\xee\xff\x00\x01\x02\x03\x00\x00",
        );
        test_serde(
            Versionstamp::complete(b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a".clone(), 657),
            b"\x33\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x02\x91",
        );
        test_serde(0, b"\x14");
        test_serde(1, b"\x15\x01");
        test_serde(-1, b"\x13\xfe");
        test_serde(255, b"\x15\xff");
        test_serde(-255, b"\x13\x00");
        test_serde(256, b"\x16\x01\x00");
        test_serde(-256, b"\x12\xfe\xff");
        test_serde(65536, b"\x17\x01\x00\x00");
        test_serde(-65536, b"\x11\xfe\xff\xff");
        test_serde(i64::max_value(), b"\x1C\x7f\xff\xff\xff\xff\xff\xff\xff");
        test_serde(
            i64::max_value() as u64 + 1,
            b"\x1C\x80\x00\x00\x00\x00\x00\x00\x00",
        );
        test_serde(u64::max_value(), b"\x1C\xff\xff\xff\xff\xff\xff\xff\xff");
        test_serde(
            u128::max_value(),
            b"\x1D\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",
        );
        test_serde(
            u64::max_value() as u128 + 1,
            b"\x1D\x09\x01\x00\x00\x00\x00\x00\x00\x00\x00",
        );
        test_serde(
            u64::max_value() as i128 + 1,
            b"\x1D\x09\x01\x00\x00\x00\x00\x00\x00\x00\x00",
        );
        test_serde(
            i64::min_value() as i128 + 1,
            b"\x0C\x80\x00\x00\x00\x00\x00\x00\x00",
        );
        test_serde(
            i64::min_value() as i128 - 1,
            b"\x0C\x7f\xff\xff\xff\xff\xff\xff\xfe",
        );
        test_serde(
            -(u64::max_value() as i128),
            b"\x0C\x00\x00\x00\x00\x00\x00\x00\x00",
        );
        test_serde(
            -(u64::max_value() as i128) - 1,
            b"\x0b\xf6\xfe\xff\xff\xff\xff\xff\xff\xff\xff",
        );
        test_serde(
            -(u64::max_value() as i128) - 2,
            b"\x0b\xf6\xfe\xff\xff\xff\xff\xff\xff\xff\xfe",
        );
        test_serde(
            (u64::max_value() as i128) * -2,
            b"\x0b\xf6\xfe\x00\x00\x00\x00\x00\x00\x00\x01",
        );
        test_serde(
            (u64::max_value() as i128) * 2,
            b"\x1d\x09\x01\xff\xff\xff\xff\xff\xff\xff\xfe",
        );
        test_serde(-4294967295i64, b"\x10\x00\x00\x00\x00");
        test_serde(
            i64::min_value() + 2,
            b"\x0C\x80\x00\x00\x00\x00\x00\x00\x01",
        );
        test_serde(
            i64::min_value() + 1,
            b"\x0C\x80\x00\x00\x00\x00\x00\x00\x00",
        );
        test_serde(i64::min_value(), b"\x0C\x7f\xff\xff\xff\xff\xff\xff\xff");
        test_serde(9252427359321063944i128, b"\x1c\x80g9\xa9np\x02\x08");
        assert!(
            match unpack::<i64>(b"\x1c\x80g9\xa9np\x02\x08").unwrap_err() {
                PackError::UnsupportedIntLength => true,
                _ => false,
            }
        );
        test_serde(
            -9252427359321063944i128,
            b"\x0c\x7f\x98\xc6V\x91\x8f\xfd\xf7",
        );
        assert!(
            match unpack::<i64>(b"\x0c\x7f\x98\xc6V\x91\x8f\xfd\xf7").unwrap_err() {
                PackError::UnsupportedIntLength => true,
                _ => false,
            }
        );
        test_serde(
            u64::max_value() as i128,
            b"\x1c\xff\xff\xff\xff\xff\xff\xff\xff",
        );
        assert!(
            match unpack::<i64>(b"\x1c\xff\xff\xff\xff\xff\xff\xff\xff").unwrap_err() {
                PackError::UnsupportedIntLength => true,
                _ => false,
            }
        );
        test_serde(
            -(u64::max_value() as i128),
            b"\x0c\x00\x00\x00\x00\x00\x00\x00\x00",
        );
        assert!(
            match unpack::<i64>(b"\x0c\x00\x00\x00\x00\x00\x00\x00\x00").unwrap_err() {
                PackError::UnsupportedIntLength => true,
                _ => false,
            }
        );
        test_serde(
            (i64::max_value() as i128) + 1,
            b"\x1c\x80\x00\x00\x00\x00\x00\x00\x00",
        );
        assert!(
            match unpack::<i64>(b"\x1c\x80\x00\x00\x00\x00\x00\x00\x00").unwrap_err() {
                PackError::UnsupportedIntLength => true,
                _ => false,
            }
        );
        test_serde(
            (i64::min_value() as i128) - 1,
            b"\x0c\x7f\xff\xff\xff\xff\xff\xff\xfe",
        );
        assert!(
            match unpack::<i64>(b"\x0c\x7f\xff\xff\xff\xff\xff\xff\xfe").unwrap_err() {
                PackError::UnsupportedIntLength => true,
                _ => false,
            }
        );
    }
    #[cfg(feature = "num-bigint")]
    #[test]
    fn test_bigint() {
        use num_bigint::{BigInt, BigUint};
        
        test_serde(BigInt::from(0i64), &[INTZERO]);
        test_serde(BigUint::from(0u64), &[INTZERO]);
        test_serde(BigInt::from(1i64), &[0x15, 1]);
        test_serde(BigUint::from(1u64), &[0x15, 1]);
        test_serde(BigInt::from(-1i64), &[0x13, 254]);
        test_serde(BigInt::from(100i64), &[0x15, 100]);
        test_serde(BigUint::from(100u64), &[0x15, 100]);
        test_serde(BigInt::from(10000i32), &[0x16, 39, 16]);
        test_serde(BigUint::from(10000u32), &[0x16, 39, 16]);
        test_serde(BigInt::from(-100i16), &[19, 155]);
        test_serde(BigInt::from(-10000i64), &[18, 216, 239]);
        test_serde(BigInt::from(-1000000i64), &[17, 240, 189, 191]);
        
        test_serde(BigInt::from(255u16), &[0x15, 255]);
        test_serde(BigUint::from(255u16), &[0x15, 255]);
        test_serde(BigInt::from(256i32), &[0x16, 1, 0]);
        test_serde(BigInt::from(-255i16), &[0x13, 0]);
        test_serde(BigInt::from(-256i64), &[0x12, 254, 255]);
        test_serde(BigInt::from(0), b"\x14");
        test_serde(BigUint::from(0u64), b"\x14");
        test_serde(BigInt::from(1), b"\x15\x01");
        test_serde(BigUint::from(1u64), b"\x15\x01");
        test_serde(BigInt::from(-1), b"\x13\xfe");
        test_serde(BigInt::from(255), b"\x15\xff");
        test_serde(BigUint::from(255u64), b"\x15\xff");
        test_serde(BigInt::from(-255), b"\x13\x00");
        test_serde(BigInt::from(256), b"\x16\x01\x00");
        test_serde(BigUint::from(256u64), b"\x16\x01\x00");
        test_serde(BigInt::from(-256), b"\x12\xfe\xff");
        test_serde(BigInt::from(65536), b"\x17\x01\x00\x00");
        test_serde(BigUint::from(65536u64), b"\x17\x01\x00\x00");
        test_serde(BigInt::from(-65536), b"\x11\xfe\xff\xff");
        test_serde(
            BigInt::from(i64::max_value()),
            b"\x1C\x7f\xff\xff\xff\xff\xff\xff\xff",
        );
        test_serde(
            BigUint::from(i64::max_value() as u64),
            b"\x1C\x7f\xff\xff\xff\xff\xff\xff\xff",
        );
        test_serde(
            BigInt::from(i64::max_value() as u64 + 1),
            b"\x1C\x80\x00\x00\x00\x00\x00\x00\x00",
        );
        test_serde(
            BigUint::from(i64::max_value() as u64 + 1),
            b"\x1C\x80\x00\x00\x00\x00\x00\x00\x00",
        );
        test_serde(
            BigInt::from(u64::max_value()),
            b"\x1C\xff\xff\xff\xff\xff\xff\xff\xff",
        );
        test_serde(
            BigUint::from(u64::max_value()),
            b"\x1C\xff\xff\xff\xff\xff\xff\xff\xff",
        );
        test_serde(
            BigInt::from(u128::max_value()),
            b"\x1D\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",
        );
        test_serde(
            BigUint::from(u128::max_value()),
            b"\x1D\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",
        );
        test_serde(
            BigInt::from(u64::max_value() as u128 + 1),
            b"\x1D\x09\x01\x00\x00\x00\x00\x00\x00\x00\x00",
        );
        test_serde(
            BigUint::from(u64::max_value() as u128 + 1),
            b"\x1D\x09\x01\x00\x00\x00\x00\x00\x00\x00\x00",
        );
        test_serde(
            BigInt::from(u64::max_value() as i128 + 1),
            b"\x1D\x09\x01\x00\x00\x00\x00\x00\x00\x00\x00",
        );
        test_serde(
            BigUint::from(u64::max_value() as u128 + 1),
            b"\x1D\x09\x01\x00\x00\x00\x00\x00\x00\x00\x00",
        );
        test_serde(
            BigInt::from(i64::min_value() as i128 + 1),
            b"\x0C\x80\x00\x00\x00\x00\x00\x00\x00",
        );
        test_serde(
            BigInt::from(i64::min_value() as i128 - 1),
            b"\x0C\x7f\xff\xff\xff\xff\xff\xff\xfe",
        );
        test_serde(
            BigInt::from(-(u64::max_value() as i128)),
            b"\x0C\x00\x00\x00\x00\x00\x00\x00\x00",
        );
        test_serde(
            BigInt::from(-(u64::max_value() as i128) - 1),
            b"\x0b\xf6\xfe\xff\xff\xff\xff\xff\xff\xff\xff",
        );
        test_serde(
            BigInt::from(-(u64::max_value() as i128) - 2),
            b"\x0b\xf6\xfe\xff\xff\xff\xff\xff\xff\xff\xfe",
        );
        test_serde(
            BigInt::from((u64::max_value() as i128) * -2),
            b"\x0b\xf6\xfe\x00\x00\x00\x00\x00\x00\x00\x01",
        );
        test_serde(
            BigInt::from((u64::max_value() as i128) * 2),
            b"\x1d\x09\x01\xff\xff\xff\xff\xff\xff\xff\xfe",
        );
        test_serde(BigInt::from(-4294967295i64), b"\x10\x00\x00\x00\x00");
        test_serde(
            BigInt::from(i64::min_value() + 2),
            b"\x0C\x80\x00\x00\x00\x00\x00\x00\x01",
        );
        test_serde(
            BigInt::from(i64::min_value() + 1),
            b"\x0C\x80\x00\x00\x00\x00\x00\x00\x00",
        );
        test_serde(
            BigInt::from(i64::min_value()),
            b"\x0C\x7f\xff\xff\xff\xff\xff\xff\xff",
        );
        test_serde(
            Element::BigInt(9252427359321063944i128.into()),
            b"\x1c\x80g9\xa9np\x02\x08",
        );
        test_serde(
            Element::BigInt((-9252427359321063944i128).into()),
            b"\x0c\x7f\x98\xc6V\x91\x8f\xfd\xf7",
        );
    }
    #[cfg(feature = "uuid")]
    #[test]
    fn test_uuid() {
        use uuid::Uuid;
        test_serde(
            Element::Uuid(
                Uuid::from_slice(
                    b"\xba\xff\xff\xff\xff\x5e\xba\x11\x00\x00\x00\x00\x5c\xa1\xab\x1e",
                )
                .unwrap(),
            ),
            b"\x30\xba\xff\xff\xff\xff\x5e\xba\x11\x00\x00\x00\x00\x5c\xa1\xab\x1e",
        );
    }
    #[test]
    fn test_bindingtester() {
        test_serde("NEW_TRANSACTION".to_string(), b"\x02NEW_TRANSACTION\x00");
        test_serde(
            vec!["NEW_TRANSACTION".to_string()],
            b"\x02NEW_TRANSACTION\x00",
        );
        test_serde(
            vec![
                Element::String(Cow::Borrowed("PUSH")),
                Element::Bytes(Bytes::from(
                    b"\x01tester_output\x00\x01results\x00\x14".as_ref(),
                )),
            ],
            b"\x02PUSH\x00\x01\x01tester_output\x00\xff\x01results\x00\xff\x14\x00",
        );
        test_serde(
            vec![Element::String(Cow::Borrowed("PUSH")), Element::Nil],
            b"\x02PUSH\x00\x00",
        );
        test_serde(
            vec![
                Element::String(Cow::Borrowed("PUSH")),
                Element::Tuple(vec![
                    Element::Nil,
                    Element::Float(3299069000000.0),
                    Element::Float(-0.000000000000000000000000000000000000011883096),
                ]),
            ],
            b"\x02PUSH\x00\x05\x00\xff \xd4@\x07\xf5 \x7f~\x9a\xc2\x00",
        );
        test_serde(
            vec![
                Element::String(Cow::Borrowed("PUSH")),
                Element::Int(-133525682914243904),
            ],
            b"\x02PUSH\x00\x0c\xfe%\x9f\x19M\x81J\xbf",
        );
        test_serde(
            Element::Tuple(vec![Element::Nil, Element::Nil]),
            b"\x00\x00",
        );
        test_serde(
            Element::Tuple(vec![
                Element::String(Cow::Borrowed("PUSH")),
                Element::Tuple(vec![Element::Double(-8.251343508909708e-15)]),
            ]),
            b"\x02PUSH\x00\x05!B\xfdkl\x9f\xcc\x8eK\x00",
        );
    }
    #[test]
    fn test_element() {
        test_serde(Element::Bool(true), &[TRUE]);
        test_serde(Element::Bool(false), &[FALSE]);
        test_serde(Element::Int(-1), &[0x13, 254]);
        test_serde(
            Element::Versionstamp(Versionstamp::complete(
                b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a".clone(),
                657,
            )),
            b"\x33\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x02\x91",
        );
        test_serde(
            (Element::Versionstamp(Versionstamp::complete(
                b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a".clone(),
                657,
            )),),
            b"\x33\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x02\x91",
        );
        test_serde(
            (Element::Versionstamp(Versionstamp::complete(
                b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a".clone(),
                657,
            )),),
            b"\x33\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x02\x91",
        );
        test_serde(
            vec![Element::Bool(true), Element::Bool(false)],
            &[TRUE, FALSE],
        );
        test_serde(
            vec![Element::Tuple(vec![
                Element::Bool(true),
                Element::Bool(false),
            ])],
            &[NESTED, TRUE, FALSE, NIL],
        );
        test_serde(Vec::<Element>::new(), &[]);
        test_serde(Element::Tuple(vec![]), &[]);
    }
    #[test]
    fn test_verstionstamp() {
        assert_eq!(
            Bytes::from(pack(&("foo", Versionstamp::incomplete(0)))),
            Bytes::from(&b"\x02foo\x00\x33\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00"[..])
        );
        assert_eq!(
            Bytes::from(pack_with_versionstamp(&(
                "foo",
                Versionstamp::incomplete(0)
            ))),
            Bytes::from(
                &b"\x02foo\x00\x33\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x06\x00\x00\x00"
                    [..]
            )
        );
    }
}