#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum NumberModel {
FloatOnly,
Dual,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum LuaVersion {
V51,
V52,
V53,
V54,
V55,
}
impl Default for LuaVersion {
fn default() -> Self {
LuaVersion::V54
}
}
impl LuaVersion {
pub fn number_model(self) -> NumberModel {
match self {
LuaVersion::V51 | LuaVersion::V52 => NumberModel::FloatOnly,
LuaVersion::V53 | LuaVersion::V54 | LuaVersion::V55 => NumberModel::Dual,
}
}
pub fn honors_name_metafield(self) -> bool {
!matches!(self, LuaVersion::V51 | LuaVersion::V52)
}
pub fn lines_returns_to_be_closed(self) -> bool {
matches!(self, LuaVersion::V54 | LuaVersion::V55)
}
pub fn is_supported(self) -> bool {
matches!(
self,
LuaVersion::V51 | LuaVersion::V52 | LuaVersion::V53 | LuaVersion::V54 | LuaVersion::V55
)
}
pub fn version_str(self) -> &'static str {
match self {
LuaVersion::V51 => "Lua 5.1",
LuaVersion::V52 => "Lua 5.2",
LuaVersion::V53 => "Lua 5.3",
LuaVersion::V54 => "Lua 5.4",
LuaVersion::V55 => "Lua 5.5",
}
}
pub fn luac_version_byte(self) -> u8 {
match self {
LuaVersion::V51 => 0x51,
LuaVersion::V52 => 0x52,
LuaVersion::V53 => 0x53,
LuaVersion::V54 => 0x54,
LuaVersion::V55 => 0x55,
}
}
pub fn supports(self, f: Feature) -> bool {
use Feature::*;
use LuaVersion::*;
match f {
IntegerSubtype | NativeBitwise | Utf8Lib | StringPack => {
matches!(self, V53 | V54 | V55)
}
EnvSandbox | GotoLabels | TableLenMetamethod | GcIsRunning => {
matches!(self, V52 | V53 | V54 | V55)
}
FenvSandbox => self == V51,
Bit32Lib => matches!(self, V52 | V53),
CloseAttribute | ConstAttribute | CoroutineClose | WarnFunction => {
matches!(self, V54 | V55)
}
GcParam | GlobalKeyword | NamedVararg | TableCreate => self == V55,
}
}
pub fn features(self) -> impl Iterator<Item = Feature> {
Feature::ALL.iter().copied().filter(move |f| self.supports(*f))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Feature {
IntegerSubtype,
EnvSandbox,
FenvSandbox,
GotoLabels,
NativeBitwise,
Bit32Lib,
Utf8Lib,
StringPack,
CloseAttribute,
ConstAttribute,
CoroutineClose,
WarnFunction,
TableLenMetamethod,
GcIsRunning,
GcParam,
GlobalKeyword,
NamedVararg,
TableCreate,
}
impl Feature {
pub const ALL: [Feature; 18] = [
Feature::IntegerSubtype,
Feature::EnvSandbox,
Feature::FenvSandbox,
Feature::GotoLabels,
Feature::NativeBitwise,
Feature::Bit32Lib,
Feature::Utf8Lib,
Feature::StringPack,
Feature::CloseAttribute,
Feature::ConstAttribute,
Feature::CoroutineClose,
Feature::WarnFunction,
Feature::TableLenMetamethod,
Feature::GcIsRunning,
Feature::GcParam,
Feature::GlobalKeyword,
Feature::NamedVararg,
Feature::TableCreate,
];
pub fn name(self) -> &'static str {
match self {
Feature::IntegerSubtype => "integer subtype (math.type)",
Feature::EnvSandbox => "_ENV sandboxing",
Feature::FenvSandbox => "setfenv/getfenv",
Feature::GotoLabels => "goto/labels",
Feature::NativeBitwise => "native bitwise operators",
Feature::Bit32Lib => "bit32 library",
Feature::Utf8Lib => "utf8 library",
Feature::StringPack => "string.pack",
Feature::CloseAttribute => "<close> attribute",
Feature::ConstAttribute => "<const> attribute",
Feature::CoroutineClose => "coroutine.close",
Feature::WarnFunction => "warn",
Feature::TableLenMetamethod => "__len on tables",
Feature::GcIsRunning => "collectgarbage('isrunning')",
Feature::GcParam => "collectgarbage('param')",
Feature::GlobalKeyword => "global declarations",
Feature::NamedVararg => "named vararg tables",
Feature::TableCreate => "table.create",
}
}
}
impl core::fmt::Display for Feature {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(self.name())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Unsupported {
pub feature: Feature,
pub version: LuaVersion,
}
impl core::fmt::Display for Unsupported {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"{} is not available in {}",
self.feature,
self.version.version_str()
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn feature_all_has_no_duplicates() {
for (i, a) in Feature::ALL.iter().enumerate() {
for b in &Feature::ALL[i + 1..] {
assert_ne!(a, b, "duplicate feature in Feature::ALL");
}
}
}
#[test]
fn default_is_v54() {
assert_eq!(LuaVersion::default(), LuaVersion::V54);
}
#[test]
fn number_model_split() {
assert_eq!(LuaVersion::V51.number_model(), NumberModel::FloatOnly);
assert_eq!(LuaVersion::V52.number_model(), NumberModel::FloatOnly);
assert_eq!(LuaVersion::V53.number_model(), NumberModel::Dual);
assert_eq!(LuaVersion::V54.number_model(), NumberModel::Dual);
assert_eq!(LuaVersion::V55.number_model(), NumberModel::Dual);
}
#[test]
fn version_str_and_byte() {
assert_eq!(LuaVersion::V54.version_str(), "Lua 5.4");
assert_eq!(LuaVersion::V54.luac_version_byte(), 0x54);
assert_eq!(LuaVersion::V53.version_str(), "Lua 5.3");
assert_eq!(LuaVersion::V53.luac_version_byte(), 0x53);
}
}