use std::mem;
use crate::{Decoder, MltError, MltResult};
pub trait Decode<Parsed>: Sized {
fn decode(self, decoder: &mut Decoder) -> MltResult<Parsed>;
}
mod sealed {
pub trait Sealed {}
}
pub trait DecodeState: sealed::Sealed {
type LazyOrParsed<Raw, Parsed>;
}
#[derive(Debug, Clone, PartialEq)]
pub struct Lazy;
#[derive(Debug, Clone, PartialEq)]
pub struct Parsed;
impl sealed::Sealed for Lazy {}
impl sealed::Sealed for Parsed {}
impl DecodeState for Lazy {
type LazyOrParsed<Raw, Parsed> = LazyParsed<Raw, Parsed>;
}
impl DecodeState for Parsed {
type LazyOrParsed<Raw, Parsed> = Parsed;
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(all(not(test), feature = "arbitrary"), derive(arbitrary::Arbitrary))]
pub enum LazyParsed<Raw, Parsed> {
Raw(Raw),
Parsed(Parsed),
ParsingFailed,
}
impl<Raw: Decode<Parsed>, Parsed> LazyParsed<Raw, Parsed> {
pub fn decode(&mut self, decoder: &mut Decoder) -> MltResult<&mut Parsed> {
match self {
Self::Parsed(v) => Ok(v),
Self::Raw(_) => {
let Self::Raw(raw) = mem::replace(self, Self::ParsingFailed) else {
unreachable!();
};
*self = Self::Parsed(raw.decode(decoder)?);
let Self::Parsed(v) = self else {
unreachable!()
};
Ok(v)
}
Self::ParsingFailed => Err(MltError::PriorParseFailure),
}
}
pub fn into_parsed(self, decoder: &mut Decoder) -> MltResult<Parsed> {
match self {
Self::Parsed(v) => Ok(v),
Self::Raw(raw) => raw.decode(decoder),
Self::ParsingFailed => Err(MltError::PriorParseFailure),
}
}
pub fn as_parsed(&self) -> MltResult<&Parsed> {
match self {
Self::Parsed(v) => Ok(v),
Self::Raw(_) => Err(MltError::NotDecoded("enc_dec value")), Self::ParsingFailed => Err(MltError::PriorParseFailure),
}
}
}