use crate::version::LuaVersion;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(super) enum Num {
Int,
SizeT,
Instruction,
Integer,
Number,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub(super) enum Bad {
Truncated,
NotBinary,
Version,
Format,
Corrupted,
Size(Num),
NumFormat(Num),
IntOverflow,
Constant,
Code(String),
}
impl From<String> for Bad {
fn from(detail: String) -> Bad {
Bad::Code(detail)
}
}
impl From<&str> for Bad {
fn from(detail: &str) -> Bad {
Bad::Code(detail.to_string())
}
}
impl Bad {
pub(super) fn render(&self, version: LuaVersion) -> String {
let framed = match version {
LuaVersion::Lua51 => format!("{} in precompiled chunk", self.why_51()),
LuaVersion::Lua52 => format!("{} precompiled chunk", self.why_52()),
LuaVersion::Lua53 => format!("{} precompiled chunk", self.why_53()),
LuaVersion::Lua54 => return format!("bad binary format ({})", self.why_54()),
LuaVersion::Lua55 | LuaVersion::MacroLua => {
return format!("bad binary format ({})", self.why_55());
}
};
match self {
Bad::Code(d) => format!("{framed} ({d})"),
_ => framed,
}
}
fn why_51(&self) -> String {
match self {
Bad::Truncated => "unexpected end".to_string(),
Bad::IntOverflow => "bad integer".to_string(),
Bad::Constant => "bad constant".to_string(),
Bad::Code(_) => "bad code".to_string(),
_ => "bad header".to_string(),
}
}
fn why_52(&self) -> String {
match self {
Bad::Truncated => "truncated".to_string(),
Bad::NotBinary => "not a".to_string(),
Bad::Version | Bad::Format => "version mismatch in".to_string(),
Bad::Size(_) | Bad::NumFormat(_) => "incompatible".to_string(),
Bad::Corrupted | Bad::IntOverflow | Bad::Constant => "corrupted".to_string(),
Bad::Code(_) => "corrupted".to_string(),
}
}
fn why_53(&self) -> String {
match self {
Bad::Truncated => "truncated".to_string(),
Bad::NotBinary => "not a".to_string(),
Bad::Version => "version mismatch in".to_string(),
Bad::Format => "format mismatch in".to_string(),
Bad::Size(n) => format!("{} size mismatch in", c_name(*n)),
Bad::NumFormat(Num::Number) => "float format mismatch in".to_string(),
Bad::NumFormat(_) => "endianness mismatch in".to_string(),
Bad::Corrupted | Bad::IntOverflow | Bad::Constant => "corrupted".to_string(),
Bad::Code(_) => "corrupted".to_string(),
}
}
fn why_54(&self) -> String {
match self {
Bad::Size(n) => format!("{} size mismatch", c_name(*n)),
Bad::NumFormat(Num::Number) => "float format mismatch".to_string(),
Bad::NumFormat(_) => "integer format mismatch".to_string(),
_ => self.why_modern(),
}
}
fn why_55(&self) -> String {
match self {
Bad::Size(n) => format!("{} size mismatch", name_55(*n)),
Bad::NumFormat(n) => format!("{} format mismatch", name_55(*n)),
_ => self.why_modern(),
}
}
fn why_modern(&self) -> String {
match self {
Bad::Truncated => "truncated chunk".to_string(),
Bad::NotBinary => "not a binary chunk".to_string(),
Bad::Version => "version mismatch".to_string(),
Bad::Format => "format mismatch".to_string(),
Bad::Corrupted => "corrupted chunk".to_string(),
Bad::IntOverflow => "integer overflow".to_string(),
Bad::Constant => "invalid constant".to_string(),
Bad::Code(d) => d.clone(),
Bad::Size(_) | Bad::NumFormat(_) => unreachable!("worded per dialect"),
}
}
}
fn c_name(n: Num) -> &'static str {
match n {
Num::Int => "int",
Num::SizeT => "size_t",
Num::Instruction => "Instruction",
Num::Integer => "lua_Integer",
Num::Number => "lua_Number",
}
}
fn name_55(n: Num) -> &'static str {
match n {
Num::Int => "int",
Num::SizeT => "size_t",
Num::Instruction => "instruction",
Num::Integer => "Lua integer",
Num::Number => "Lua number",
}
}
pub(super) fn lundump_name(chunkname: &[u8]) -> &[u8] {
match chunkname.first() {
Some(b'@' | b'=') => &chunkname[1..],
Some(0x1b) => b"binary string",
_ => chunkname,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_refusal_without_puc_wording_keeps_its_detail() {
let bad = Bad::Code("register 9 out of range".to_string());
let got: Vec<String> = [
LuaVersion::Lua51,
LuaVersion::Lua52,
LuaVersion::Lua53,
LuaVersion::Lua54,
LuaVersion::Lua55,
]
.into_iter()
.map(|v| bad.render(v))
.collect();
assert_eq!(
got,
[
"bad code in precompiled chunk (register 9 out of range)",
"corrupted precompiled chunk (register 9 out of range)",
"corrupted precompiled chunk (register 9 out of range)",
"bad binary format (register 9 out of range)",
"bad binary format (register 9 out of range)",
]
);
}
#[test]
fn chunk_names_follow_lundump() {
assert_eq!(lundump_name(b"@a/b.lua"), b"a/b.lua");
assert_eq!(lundump_name(b"=stdin"), b"stdin");
assert_eq!(lundump_name(b"\x1bLua..."), b"binary string");
assert_eq!(lundump_name(b"plain"), b"plain");
}
}