use bytes::{Buf, BufMut};
use bytes::{Bytes, BytesMut};
const VERSIONSTAMP_TR_VERSION_LEN: usize = 10;
const VERSIONSTAMP_USER_VERSION_LEN: usize = 2;
#[derive(Clone, Ord, Eq, PartialOrd, PartialEq, Debug)]
pub struct Versionstamp {
complete: bool,
tr_version: Bytes,
user_version: u16,
}
impl Versionstamp {
pub fn complete(tr_version: Bytes, user_version: u16) -> Versionstamp {
if tr_version.len() != VERSIONSTAMP_TR_VERSION_LEN {
panic!("Global version has invalid length {}", tr_version.len());
}
let complete = true;
Versionstamp {
complete,
tr_version,
user_version,
}
}
pub fn from_bytes(version_bytes: Bytes) -> Versionstamp {
if version_bytes.len() != VERSIONSTAMP_TR_VERSION_LEN + VERSIONSTAMP_USER_VERSION_LEN {
panic!(
"Versionstamp bytes must have length {}",
VERSIONSTAMP_TR_VERSION_LEN + VERSIONSTAMP_USER_VERSION_LEN
);
}
let mut complete = false;
version_bytes[0..VERSIONSTAMP_TR_VERSION_LEN]
.iter()
.for_each(|x| {
if *x != 0xFF {
complete = true;
}
});
let tr_version = version_bytes.slice(0..VERSIONSTAMP_TR_VERSION_LEN);
let user_version = version_bytes.slice(VERSIONSTAMP_TR_VERSION_LEN..).get_u16();
Versionstamp {
complete,
tr_version,
user_version,
}
}
pub fn incomplete(user_version: u16) -> Versionstamp {
let complete = false;
let tr_version = Bytes::from_static(&b"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"[..]);
Versionstamp {
complete,
tr_version,
user_version,
}
}
pub fn get_bytes(&self) -> Bytes {
let mut buf =
BytesMut::with_capacity(VERSIONSTAMP_TR_VERSION_LEN + VERSIONSTAMP_USER_VERSION_LEN);
buf.put(self.tr_version.clone());
buf.put_u16(self.user_version);
buf.into()
}
pub fn get_transaction_version(&self) -> Bytes {
self.tr_version.clone()
}
pub fn get_user_version(&self) -> u16 {
self.user_version
}
pub fn is_complete(&self) -> bool {
self.complete
}
}
#[cfg(test)]
mod tests {
use bytes::Bytes;
use super::Versionstamp;
#[test]
fn complete() {
assert!(std::panic::catch_unwind(|| {
Versionstamp::complete(Bytes::from_static(&b"invalid"[..]), 0)
})
.is_err());
assert_eq!(
Versionstamp::complete(
Bytes::from_static(&b"\xAA\xBB\xCC\xDD\xEE\xFF\x00\x01\x02\x03"[..]),
0
),
Versionstamp {
complete: true,
tr_version: Bytes::from_static(&b"\xAA\xBB\xCC\xDD\xEE\xFF\x00\x01\x02\x03"[..]),
user_version: 0
}
);
}
#[test]
fn from_bytes() {
assert!(std::panic::catch_unwind(|| {
Versionstamp::from_bytes(Bytes::from_static(&b"invalid"[..]))
})
.is_err());
assert_eq!(
Versionstamp::from_bytes(Bytes::from_static(
&b"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x02\x91"[..]
)),
Versionstamp::incomplete(657)
);
assert_eq!(
Versionstamp::from_bytes(Bytes::from_static(
&b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x02\x91"[..]
)),
Versionstamp::complete(
Bytes::from_static(&b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A"[..]),
657
)
);
}
#[test]
fn incomplete() {
assert_eq!(
Versionstamp::incomplete(657),
Versionstamp {
complete: false,
tr_version: Bytes::from_static(&b"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"[..]),
user_version: 657
}
);
}
#[test]
fn get_bytes() {
assert_eq!(
(Versionstamp::complete(
Bytes::from_static(&b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A"[..]),
657
))
.get_bytes(),
Bytes::from_static(&b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x02\x91"[..])
);
assert_eq!(
(Versionstamp::incomplete(657)).get_bytes(),
Bytes::from_static(&b"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x02\x91"[..])
);
}
#[test]
fn get_transaction_version() {
assert_eq!(
(Versionstamp::complete(
Bytes::from_static(&b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A"[..]),
657
))
.get_transaction_version(),
Bytes::from_static(&b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A"[..])
);
assert_eq!(
(Versionstamp::incomplete(657)).get_transaction_version(),
Bytes::from_static(&b"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"[..])
);
}
#[test]
fn get_user_version() {
assert_eq!(
(Versionstamp::complete(
Bytes::from_static(&b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A"[..]),
657
))
.get_user_version(),
657
);
assert_eq!((Versionstamp::incomplete(657)).get_user_version(), 657);
}
#[test]
fn is_complete() {
assert!((Versionstamp::complete(
Bytes::from_static(&b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A"[..]),
657
))
.is_complete());
assert!(!(Versionstamp::incomplete(657)).is_complete());
}
}