use crate::chain::ergo_box::RegisterValueError;
use crate::ergo_tree::ErgoTreeHeaderError;
use crate::mir::val_def::ValId;
use crate::mir::{constant::TryExtractFromError, expr::InvalidArgumentError};
use crate::types::type_unify::TypeUnificationError;
use super::{
constant_store::ConstantStore,
sigma_byte_reader::{SigmaByteRead, SigmaByteReader},
sigma_byte_writer::{SigmaByteWrite, SigmaByteWriter},
};
use crate::types::smethod::MethodId;
use bounded_vec::BoundedVec;
use bounded_vec::BoundedVecOutOfBounds;
use io::Cursor;
use sigma_ser::{vlq_encode, ScorexParsingError, ScorexSerializationError};
use std::convert::TryInto;
use std::io;
use thiserror::Error;
#[derive(Error, Eq, PartialEq, Debug, Clone)]
pub enum SigmaSerializationError {
#[error("IO error: {0}")]
Io(String),
#[error("serialization not yet implemented: {0}")]
NotImplementedYet(&'static str),
#[error("Unexpected value: {0:?}")]
UnexpectedValue(#[from] TryExtractFromError),
#[error("serialization not supported: {0}")]
NotSupported(String),
#[error("Scorex serialization error: {0}")]
ScorexSerializationError(#[from] ScorexSerializationError),
}
impl From<io::Error> for SigmaSerializationError {
fn from(error: io::Error) -> Self {
SigmaSerializationError::Io(error.to_string())
}
}
#[derive(Error, Eq, PartialEq, Debug, Clone)]
pub enum SigmaParsingError {
#[error("invalid op code: {0}")]
InvalidOpCode(u8),
#[error("not implemented op error: {0}")]
NotImplementedOpCode(String),
#[error("type parsing error, invalid type code: {0}({0:#04X})")]
InvalidTypeCode(u8),
#[error("vlq encode error: {0}")]
VlqEncode(#[from] vlq_encode::VlqEncodingError),
#[error("IO error: {0}")]
Io(String),
#[error("misc error: {0}")]
Misc(String),
#[error("parsing not yet implemented: {0}")]
NotImplementedYet(String),
#[error("Constant with index {0} not found in constant store")]
ConstantForPlaceholderNotFound(u32),
#[error("Value out of bounds: {0}")]
ValueOutOfBounds(String),
#[error("Tuple items out of bounds: {0}")]
TupleItemsOutOfBounds(usize),
#[error("ValDef type for an index {0:?} not found in ValDefTypeStore store")]
ValDefIdNotFound(ValId),
#[error("Invalid argument: {0:?}")]
InvalidArgument(#[from] InvalidArgumentError),
#[error("No method id {0:?} found in type companion with type id {1:?} ")]
UnknownMethodId(MethodId, u8),
#[error("parsing not supported: {0}")]
NotSupported(&'static str),
#[error("serialization error: {0}")]
SerializationError(#[from] SigmaSerializationError),
#[error("Invalid item quantity for BoundedVec: {0}")]
BoundedVecOutOfBounds(#[from] BoundedVecOutOfBounds),
#[error("Scorex parsing error: {0}")]
ScorexParsingError(#[from] ScorexParsingError),
#[error("ErgoTreeHeaderError: {0}")]
ErgoTreeHeaderError(#[from] ErgoTreeHeaderError),
#[error("Invalid register value: {0}")]
InvalidRegisterValue(#[from] RegisterValueError),
}
impl From<io::Error> for SigmaParsingError {
fn from(error: io::Error) -> Self {
SigmaParsingError::Io(error.to_string())
}
}
impl From<&io::Error> for SigmaParsingError {
fn from(error: &io::Error) -> Self {
SigmaParsingError::Io(error.to_string())
}
}
impl From<TypeUnificationError> for SigmaParsingError {
fn from(e: TypeUnificationError) -> Self {
SigmaParsingError::Misc(format!("{:?}", e))
}
}
pub type SigmaSerializeResult = Result<(), SigmaSerializationError>;
pub trait SigmaSerializable: Sized {
fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> SigmaSerializeResult;
fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, SigmaParsingError>;
fn sigma_serialize_bytes(&self) -> Result<Vec<u8>, SigmaSerializationError> {
let mut data = Vec::new();
let mut w = SigmaByteWriter::new(&mut data, None);
self.sigma_serialize(&mut w)?;
Ok(data)
}
fn sigma_parse_bytes(bytes: &[u8]) -> Result<Self, SigmaParsingError> {
let cursor = Cursor::new(bytes);
let mut sr = SigmaByteReader::new(cursor, ConstantStore::empty());
Self::sigma_parse(&mut sr)
}
}
impl<T: SigmaSerializable> SigmaSerializable for Vec<T> {
fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> SigmaSerializeResult {
w.put_u32(self.len() as u32)?;
self.iter().try_for_each(|i| i.sigma_serialize(w))
}
fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, SigmaParsingError> {
let items_count = r.get_u32()?;
let mut items = Vec::with_capacity(items_count as usize);
for _ in 0..items_count {
items.push(T::sigma_parse(r)?);
}
Ok(items)
}
}
impl<T: SigmaSerializable, const L: usize, const U: usize> SigmaSerializable
for BoundedVec<T, L, U>
{
fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> SigmaSerializeResult {
self.as_vec().sigma_serialize(w)
}
fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, SigmaParsingError> {
Ok(Vec::<T>::sigma_parse(r)?.try_into()?)
}
}
impl SigmaSerializable for u32 {
fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> SigmaSerializeResult {
w.put_u32(*self)?;
Ok(())
}
fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, SigmaParsingError> {
let v = r.get_u32()?;
Ok(v)
}
}
impl<T: SigmaSerializable> SigmaSerializable for Option<Box<T>> {
fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> SigmaSerializeResult {
match self {
Some(v) => {
w.put_u8(1)?;
v.sigma_serialize(w)
}
None => Ok(w.put_u8(0)?),
}
}
fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, SigmaParsingError> {
let tag = r.get_u8()?;
Ok(if tag != 0 {
Some(T::sigma_parse(r)?.into())
} else {
None
})
}
}
#[allow(clippy::expect_used)]
pub fn sigma_serialize_roundtrip<T: SigmaSerializable>(v: &T) -> T {
let mut data = Vec::new();
let mut w = SigmaByteWriter::new(&mut data, None);
v.sigma_serialize(&mut w).expect("serialization failed");
let cursor = Cursor::new(&mut data[..]);
let mut sr = SigmaByteReader::new(cursor, ConstantStore::empty());
T::sigma_parse(&mut sr).expect("parse failed")
}