lune_utils/
version_string.rs1use std::sync::{Arc, LazyLock};
2
3use mlua::prelude::*;
4use semver::Version;
5
6static LUAU_VERSION: LazyLock<Arc<String>> = LazyLock::new(create_luau_version_string);
7
8#[must_use]
19pub fn get_version_string(lune_version: impl AsRef<str>) -> String {
20 let lune_version = lune_version.as_ref();
21
22 assert!(!lune_version.is_empty(), "Lune version string is empty");
23 match Version::parse(lune_version) {
24 Ok(semver) => format!("Lune {semver}+{}", *LUAU_VERSION),
25 Err(e) => panic!("Lune version string is not valid semver: {e}"),
26 }
27}
28
29fn create_luau_version_string() -> Arc<String> {
30 let luau_version_full = {
32 let temp_lua = Lua::new();
33
34 let luau_version_full = temp_lua
35 .globals()
36 .get::<LuaString>("_VERSION")
37 .expect("Missing _VERSION global");
38
39 luau_version_full
40 .to_str()
41 .context("Invalid utf8 found in _VERSION global")
42 .expect("Expected _VERSION global to be a string")
43 .to_string()
44 };
45
46 assert!(
48 luau_version_full.starts_with("Luau 0."),
49 "_VERSION global is formatted incorrectly\
50 \nFound string '{luau_version_full}'"
51 );
52 let luau_version_noprefix = luau_version_full.strip_prefix("Luau 0.").unwrap().trim();
53
54 if luau_version_noprefix.is_empty() {
57 panic!(
58 "_VERSION global is missing version number\
59 \nFound string '{luau_version_full}'"
60 )
61 } else if !luau_version_noprefix.chars().all(is_valid_version_char) {
62 panic!(
63 "_VERSION global contains invalid characters\
64 \nFound string '{luau_version_full}'"
65 )
66 }
67
68 luau_version_noprefix.to_string().into()
69}
70
71fn is_valid_version_char(c: char) -> bool {
72 matches!(c, '0'..='9' | '.')
73}