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"
[..]
)
);
}
}