wows_replays 0.18.0

A parser for World of Warships replay files
Documentation
use thiserror::Error;
use wowsunpack::data::Version;

#[derive(Debug)]
pub struct Error {
    pub kind: ErrorKind,
    backtrace: Vec<ErrorKind>,
}

#[derive(Error, Debug)]
#[non_exhaustive]
pub enum ErrorKind {
    #[error("Nom error")]
    Nom {
        err: nom::error::ErrorKind,
        input: Vec<u8>,
    },
    #[error("Error parsing json")]
    Serde {
        #[from]
        err: serde_json::Error,
    },
    #[error("Error interpreting UTF-8 string")]
    Utf8Error {
        #[from]
        err: std::str::Utf8Error,
    },
    #[error("Error interpreting UTF-8 string")]
    FromUtf8Error {
        #[from]
        err: std::string::FromUtf8Error,
    },
    #[error("Unsupported replay file version found")]
    UnsupportedReplayVersion(String),
    #[error("Unable to process packet")]
    UnableToProcessPacket {
        supertype: u32,
        subtype: u32,
        reason: String,
        packet: Vec<u8>,
    },
    #[error("Could not parse RPC value")]
    UnableToParseRpcValue {
        method: String,
        argnum: usize,
        argtype: String,
        packet: Vec<u8>,
        error: String,
    },
    #[error("Unknown FixedDict flag")]
    UnknownFixedDictFlag { flag: u8, packet: Vec<u8> },
    #[error("Internal prop set on unsupported entity")]
    UnsupportedInternalPropSet {
        entity_id: u32,
        entity_type: String,
        payload: Vec<u8>,
    },
    #[error("Data file not found")]
    DatafileNotFound { version: Version, path: String },
    #[error("Decoder ring failure")]
    DecoderRingFailure(String),
    #[error("Unable to process packet")]
    ParsingFailure(String),
    #[error("IO error")]
    IoError {
        #[from]
        err: std::io::Error,
    },
}

impl nom::error::ParseError<&[u8]> for Error {
    fn from_error_kind(input: &[u8], kind: nom::error::ErrorKind) -> Self {
        Self {
            kind: ErrorKind::Nom {
                err: kind,
                input: input.to_vec(),
            },
            backtrace: Vec::new(),
        }
    }

    fn append(input: &[u8], kind: nom::error::ErrorKind, mut other: Self) -> Self {
        other
            .backtrace
            .push(Self::from_error_kind(input, kind).kind);
        other
    }
}

impl std::convert::From<nom::Err<Error>> for ErrorKind {
    fn from(x: nom::Err<Error>) -> ErrorKind {
        match x {
            nom::Err::<Error>::Incomplete(_) => {
                panic!("We can't handle incomplete replay files");
            }
            nom::Err::<Error>::Error(e) => e.kind,
            nom::Err::<Error>::Failure(e) => e.kind,
        }
    }
}

impl std::convert::From<std::str::Utf8Error> for Error {
    fn from(x: std::str::Utf8Error) -> Error {
        Error {
            kind: x.into(),
            backtrace: vec![],
        }
    }
}

impl std::convert::From<std::string::FromUtf8Error> for Error {
    fn from(x: std::string::FromUtf8Error) -> Error {
        Error {
            kind: x.into(),
            backtrace: vec![],
        }
    }
}

impl std::convert::From<serde_json::Error> for Error {
    fn from(x: serde_json::Error) -> Error {
        Error {
            kind: x.into(),
            backtrace: vec![],
        }
    }
}

pub type IResult<I, T> = nom::IResult<I, T, Error>;

pub fn failure_from_kind(kind: ErrorKind) -> nom::Err<Error> {
    nom::Err::Failure(Error {
        kind,
        backtrace: vec![],
    })
}