lua_types/version.rs
1//! `LuaVersion` — the single source of truth for which Lua language version a
2//! runtime instance speaks.
3//!
4//! This lives in `lua-types`, the lowest shared crate, so every layer above
5//! (parser, compiler, VM, stdlib, runtime) can name the version without a
6//! dependency cycle. Per the multi-version architecture decision
7//! (`specs/MULTIVERSION_ARCHITECTURE_DECISION.md` §4, §5), the version is a
8//! *backend selector* threaded from construction; it never appears in a public
9//! embedding-API type.
10
11/// The numeric model a version uses for Lua numbers.
12///
13/// This is the single sharpest behavioral axis across versions: 5.1/5.2 are
14/// float-only (one `number` type, every value an `f64`, no `math.type`), while
15/// 5.3/5.4/5.5 carry the dual integer/float subtype.
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
17pub enum NumberModel {
18 /// One `number` type; every numeric value is an `f64`. Lua 5.1/5.2.
19 FloatOnly,
20 /// Distinct integer (`i64`) and float (`f64`) subtypes. Lua 5.3/5.4/5.5.
21 Dual,
22}
23
24/// Which Lua language version a runtime instance speaks.
25///
26/// `Default` is [`LuaVersion::V54`] — the version this codebase currently
27/// implements end-to-end — so that `Lua::new()` and any other defaulted
28/// construction keeps the existing 5.4 behavior.
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
30#[non_exhaustive]
31pub enum LuaVersion {
32 /// Lua 5.1 — float-only, `fenv`-based globals. Deferred (separate core).
33 V51,
34 /// Lua 5.2 — float-only, modern `_ENV` globals. Deferred (separate core).
35 V52,
36 /// Lua 5.3 — dual subtype, modern `_ENV`. Deferred.
37 V53,
38 /// Lua 5.4 — the implemented baseline today.
39 V54,
40 /// Lua 5.5 — dual subtype, declared-globals scope model. Deferred.
41 V55,
42}
43
44impl Default for LuaVersion {
45 fn default() -> Self {
46 LuaVersion::V54
47 }
48}
49
50impl LuaVersion {
51 /// The family-level numeric model for this version.
52 pub fn number_model(self) -> NumberModel {
53 match self {
54 LuaVersion::V51 | LuaVersion::V52 => NumberModel::FloatOnly,
55 LuaVersion::V53 | LuaVersion::V54 | LuaVersion::V55 => NumberModel::Dual,
56 }
57 }
58
59 /// Whether this version has a real backend. The modern family (5.3/5.4/5.5)
60 /// is implemented; 5.1/5.2 (the float-only legacy family) are not yet, so
61 /// they must REFUSE rather than silently run as 5.4 (which would expose
62 /// integers, `//`, `goto`, etc. that 5.1 lacks — a misleading masquerade).
63 pub fn is_supported(self) -> bool {
64 matches!(self, LuaVersion::V53 | LuaVersion::V54 | LuaVersion::V55)
65 }
66
67 /// The `_VERSION` global string for this version (e.g. `"Lua 5.4"`).
68 pub fn version_str(self) -> &'static str {
69 match self {
70 LuaVersion::V51 => "Lua 5.1",
71 LuaVersion::V52 => "Lua 5.2",
72 LuaVersion::V53 => "Lua 5.3",
73 LuaVersion::V54 => "Lua 5.4",
74 LuaVersion::V55 => "Lua 5.5",
75 }
76 }
77
78 /// The `LUAC_VERSION` byte written into a `luac`/`string.dump` header for
79 /// this version. Upstream encodes the version as `(major << 4) | minor`,
80 /// e.g. 5.4 → `0x54`.
81 pub fn luac_version_byte(self) -> u8 {
82 match self {
83 LuaVersion::V51 => 0x51,
84 LuaVersion::V52 => 0x52,
85 LuaVersion::V53 => 0x53,
86 LuaVersion::V54 => 0x54,
87 LuaVersion::V55 => 0x55,
88 }
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 #[test]
97 fn default_is_v54() {
98 assert_eq!(LuaVersion::default(), LuaVersion::V54);
99 }
100
101 #[test]
102 fn number_model_split() {
103 assert_eq!(LuaVersion::V51.number_model(), NumberModel::FloatOnly);
104 assert_eq!(LuaVersion::V52.number_model(), NumberModel::FloatOnly);
105 assert_eq!(LuaVersion::V53.number_model(), NumberModel::Dual);
106 assert_eq!(LuaVersion::V54.number_model(), NumberModel::Dual);
107 assert_eq!(LuaVersion::V55.number_model(), NumberModel::Dual);
108 }
109
110 #[test]
111 fn version_str_and_byte() {
112 assert_eq!(LuaVersion::V54.version_str(), "Lua 5.4");
113 assert_eq!(LuaVersion::V54.luac_version_byte(), 0x54);
114 assert_eq!(LuaVersion::V53.version_str(), "Lua 5.3");
115 assert_eq!(LuaVersion::V53.luac_version_byte(), 0x53);
116 }
117}
118
119// ──────────────────────────────────────────────────────────────────────────
120// PORT STATUS
121// source: (foundation — multi-version seam, not ported from .c)
122// target_crate: lua-types
123// confidence: high
124// todos: 0
125// port_notes: 0
126// unsafe_blocks: 0
127// notes: LuaVersion + NumberModel. Default = V54 preserves the
128// existing single-version behavior. Only V54 has a backend.
129// ──────────────────────────────────────────────────────────────────────────