use crate::{
alloc::{Allocator, Global},
codec::{DecodeIn, Decoder, Encode, Encoder},
error::{DecodeError, EncodeError},
};
use core::fmt;
use std::ops::{Deref, DerefMut};
pub type Version = u32;
pub trait Proof<A: Allocator = Global>: Encode + DecodeIn<A> {
const VERSION: Version;
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct VersionedProof<T: Proof<A>, A: Allocator = Global> {
pub proof: T,
allocator: A,
}
impl<T: Proof<Global>> VersionedProof<T, Global> {
pub fn new(proof: T) -> Self {
VersionedProof {
proof,
allocator: Global,
}
}
}
impl<T: Proof<A>, A: Allocator> VersionedProof<T, A> {
pub fn new_with_allocator(proof: T, allocator: A) -> Self {
VersionedProof { proof, allocator }
}
pub fn proof(&self) -> &T {
&self.proof
}
pub fn allocator(&self) -> &A {
&self.allocator
}
}
impl<T: Proof<A>, A: Allocator + Clone> DecodeIn<A> for VersionedProof<T, A> {
fn decode_in(decoder: &mut impl Decoder, alloc: A) -> Result<Self, DecodeError> {
decoder.assert_magic()?;
let version: Version = decoder.decode()?;
if version != T::VERSION {
return Err(DecodeError::BadVersion);
}
Ok(VersionedProof {
proof: T::decode_in(decoder, alloc.clone())?,
allocator: alloc,
})
}
}
impl<T: Proof<A>, A: Allocator> Encode for VersionedProof<T, A> {
fn encode(&self, encoder: &mut impl Encoder) -> Result<(), EncodeError> {
encoder.encode_magic()?;
encoder.encode(T::VERSION)?;
self.proof.encode(encoder)
}
}
impl<T: Proof<A> + fmt::Display, A: Allocator> fmt::Display for VersionedProof<T, A> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Version {} Proof {}", T::VERSION, self.proof)
}
}
impl<T: Proof<A>, A: Allocator> Deref for VersionedProof<T, A> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.proof
}
}
impl<T: Proof<A>, A: Allocator> DerefMut for VersionedProof<T, A> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.proof
}
}