Last active
September 9, 2025 14:50
-
-
Save CompeyDev/4236a0bc0b02a9c2a9deee260489f5a2 to your computer and use it in GitHub Desktop.
RAII-based fault-tolerant(?) tempfile module - ABSOLUTELY UNTESTED, WRITTEN IN A DISCORD CHATBOX, (doesn't work no `__gc` in Luau)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --> RAII-based fault-tolerant(?) tempfile module | |
| local fs = require("@lune/fs") | |
| local CHARSET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" | |
| local function randId(len: number?, rng: () -> number) | |
| local bytes = {} | |
| for _ = 1, len do | |
| local byte = math.random(1, #CHARSET) | |
| table.insert(bytes, string.sub(CHARSET, byte, byte)) | |
| end | |
| return table.concat(bytes) | |
| end | |
| -- borderline useless micro-opt but mulberry32 is simpler than pcg32, why not | |
| local function mulberry32(seed: number) | |
| local state = bit32.band(seed, 0xFFFFFFFF) | |
| return function() | |
| state = bit32.band(state + 0x6D2B79F5, 0xFFFFFFFF) | |
| local t = state | |
| t = bit32.bxor(t, bit32.rshift(t, 15)) | |
| t = bit32.band(t * (1 | t), 0xFFFFFFFF) | |
| t = bit32.bxor(t, t + bit32.rshift(t, 7)) | |
| t = bit32.bxor(t, bit32.rshift(t, 3)) | |
| return bit32.band(t, 0xFFFFFFFF) / 4294967296 | |
| end | |
| end | |
| local TempfileInner = {} | |
| type TempfileFields = { _name: string, _options: TempfileOptions, _rng: () -> number } | |
| export type Tempfile = typeof(setmetatable({} :: TempfileFields, { | |
| __index = TempfileInner, | |
| __gc = function(self: TempfileFields) end | |
| })) | |
| export type TempfileOptions = { | |
| prefix: string?, | |
| suffix: string?, | |
| idLength: number?, | |
| rng: (() -> number)?, | |
| } | |
| local function tempName(options: TempfileOptions) | |
| local prefix = options.prefix or "" | |
| local suffix = options.suffix or "" | |
| local idLength = options.idLength or 7 | |
| local rng = options.rng or mulberry32(os.time()) | |
| return `{prefix}-{randomId(idLength)}{suffix}` | |
| end | |
| function tempfile(options: TempfileOptions?): Tempfile | |
| local optionsInner = options or {} | |
| local rng = mulberry32(os.time()) | |
| optionsInner.rng = optionsInner.rng or rng | |
| return setmetatable({ | |
| _name = tempName(optionsInner) | |
| _rng = rng, | |
| _options = _options, | |
| } :: Tempfields, { | |
| __index = TempfileInner, | |
| __gc = function(self: TempfileFields) | |
| fs.removeFile(`/tmp/{self._name}`) | |
| end | |
| }) | |
| end | |
| function TempfileInner.create(self: Tempfile): string | |
| -- TODO: make this cross platform | |
| for _ = 1, 5 do | |
| local path = `/tmp/{self._name}` | |
| local ok = pcall(fs.writeFile, path, "") -- TODO: consider checking err type | |
| if not ok then | |
| self._rng = mulberry32(os.time()) | |
| self._name = tempName(self._options) | |
| continue | |
| end | |
| return path | |
| end | |
| error("Had 5 tempfile colissions, giving up, boss") | |
| end | |
| function TempfileInner.write(self: Tempfile, contents: string) | |
| local path = self:create() | |
| return fs.writeFile(path, string) | |
| end | |
| function TempfileInner.read(self: Tempfile): buffer | |
| return buffer.fromstring(fs.readFile(`/tmp/{self._name}`)) | |
| end | |
| return tempfile |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment