use derive_more::From;
use thiserror::Error;
use crate::serialization::sigma_byte_reader::SigmaByteRead;
use crate::serialization::sigma_byte_writer::SigmaByteWrite;
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct ErgoTreeHeader {
version: ErgoTreeVersion,
is_constant_segregation: bool,
has_size: bool,
}
impl ErgoTreeHeader {
pub fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> Result<(), std::io::Error> {
w.put_u8(self.serialized())
}
pub fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, ErgoTreeHeaderError> {
let header_byte = r
.get_u8()
.map_err(|e| ErgoTreeHeaderError::IoError(e.to_string()))?;
ErgoTreeHeader::new(header_byte)
}
}
impl ErgoTreeHeader {
const CONSTANT_SEGREGATION_FLAG: u8 = 0b0001_0000;
const HAS_SIZE_FLAG: u8 = 0b0000_1000;
pub fn new(header_byte: u8) -> Result<Self, ErgoTreeHeaderError> {
let version = ErgoTreeVersion::parse_version(header_byte)?;
let has_size = header_byte & Self::HAS_SIZE_FLAG != 0;
let is_constant_segregation = header_byte & Self::CONSTANT_SEGREGATION_FLAG != 0;
Ok(ErgoTreeHeader {
version,
is_constant_segregation,
has_size,
})
}
pub fn serialized(&self) -> u8 {
let mut header_byte: u8 = self.version.0;
if self.is_constant_segregation {
header_byte |= Self::CONSTANT_SEGREGATION_FLAG;
}
if self.has_size {
header_byte |= Self::HAS_SIZE_FLAG;
}
header_byte
}
pub fn v0(constant_segregation: bool) -> Self {
ErgoTreeHeader {
version: ErgoTreeVersion::V0,
is_constant_segregation: constant_segregation,
has_size: false,
}
}
pub fn v1(constant_segregation: bool) -> Self {
ErgoTreeHeader {
version: ErgoTreeVersion::V1,
is_constant_segregation: constant_segregation,
has_size: true,
}
}
pub fn is_constant_segregation(&self) -> bool {
self.is_constant_segregation
}
pub fn has_size(&self) -> bool {
self.has_size
}
pub fn version(&self) -> &ErgoTreeVersion {
&self.version
}
}
#[derive(Error, PartialEq, Eq, Debug, Clone, From)]
pub enum ErgoTreeHeaderError {
#[error("Invalid version: {0}")]
VersionError(ErgoTreeVersionError),
#[error("IO error: {0}")]
IoError(String),
}
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct ErgoTreeVersion(u8);
impl ErgoTreeVersion {
pub const VERSION_MASK: u8 = 0x07;
pub const V0: Self = ErgoTreeVersion(0);
pub const V1: Self = ErgoTreeVersion(1);
pub fn parse_version(header_byte: u8) -> Result<Self, ErgoTreeVersionError> {
let version = header_byte & ErgoTreeVersion::VERSION_MASK;
if version <= 1 {
Ok(ErgoTreeVersion(version))
} else {
Err(ErgoTreeVersionError::InvalidVersion(version))
}
}
}
#[derive(Error, PartialEq, Eq, Debug, Clone, From)]
pub enum ErgoTreeVersionError {
#[error("Invalid version: {0}")]
InvalidVersion(u8),
}