diff --git a/scada-common/util.lua b/scada-common/util.lua index b311511..97afdfd 100644 --- a/scada-common/util.lua +++ b/scada-common/util.lua @@ -4,6 +4,16 @@ local cc_strings = require("cc.strings") +local math = math +local string = string +local table = table +local os = os + +local getmetatable = getmetatable +local print = print +local tostring = tostring +local type = type + ---@class util local util = {} @@ -29,6 +39,8 @@ end --#region PRINT +local p_time = "[%H:%M:%S] " + -- print ---@param message any function util.print(message) term.write(tostring(message)) end @@ -39,11 +51,11 @@ function util.println(message) print(tostring(message)) end -- timestamped print ---@param message any -function util.print_ts(message) term.write(os.date("[%H:%M:%S] ") .. tostring(message)) end +function util.print_ts(message) term.write(os.date(p_time) .. tostring(message)) end -- timestamped print line ---@param message any -function util.println_ts(message) print(os.date("[%H:%M:%S] ") .. tostring(message)) end +function util.println_ts(message) print(os.date(p_time) .. tostring(message)) end --#endregion @@ -54,10 +66,9 @@ function util.println_ts(message) print(os.date("[%H:%M:%S] ") .. tostring(messa ---@param val any ---@return string function util.strval(val) - local t = type(val) -- this depends on Lua short-circuiting the or check for metatables (note: metatables won't have metatables) - if (t == "table" and (getmetatable(val) == nil or getmetatable(val).__tostring == nil)) or t == "function" then - return "[" .. tostring(val) .. "]" + if (util.is_tbl(val) and (getmetatable(val) == nil or getmetatable(val).__tostring == nil)) or util.is_func(val) then + return table.concat{"[", tostring(val), "]"} else return tostring(val) end end @@ -77,7 +88,7 @@ function util.pad(str, n) local lpad = math.floor((n - len) / 2) local rpad = (n - len) - lpad - return util.spaces(lpad) .. str .. util.spaces(rpad) + return table.concat{util.spaces(lpad), str, util.spaces(rpad)} end -- wrap a string into a table of lines @@ -95,9 +106,9 @@ function util.strwrap(str, limit) return cc_strings.wrap(str, limit) end ---@return string ---@diagnostic disable-next-line: unused-vararg function util.concat(...) - local str = "" - for _, v in ipairs(arg) do str = str .. util.strval(v) end - return str + local strings = {} + for i = 1, #arg do strings[i] = util.strval(arg[i]) end + return table.concat(strings) end -- alias @@ -112,6 +123,9 @@ function util.sprintf(format, ...) return string.format(format, table.unpack(arg -- luacheck: unused args +local gsub_p_a, gsub_r_a = "^(%s-%d+)(%d%d%d)", "%1,%2" +local gsub_p_b, gsub_r_b = " %s-", "" + -- format a number string with commas as the thousands separator
-- subtracts from spaces at the start if present for each comma used ---@nodiscard @@ -123,11 +137,11 @@ function util.comma_format(num) local i = 1 while i > 0 do - formatted, i = formatted:gsub("^(%s-%d+)(%d%d%d)", '%1,%2') + formatted, i = formatted:gsub(gsub_p_a, gsub_r_a) if i > 0 then commas = commas + 1 end end - local _, num_spaces = formatted:gsub(" %s-", "") + local _, num_spaces = formatted:gsub(gsub_p_b, gsub_r_b) local remove = math.min(num_spaces, commas) formatted = string.sub(formatted, remove + 1) @@ -157,7 +171,7 @@ function util.round(x) return math.floor(x + 0.5) end function util.mov_avg(length, default) local data = {} local index = 1 - local last_t = 0 ---@type number|nil + local last_t = 0 ---@type number|nil ---@class moving_average local public = {} @@ -173,9 +187,7 @@ function util.mov_avg(length, default) ---@param x number new value ---@param t number? optional last update time to prevent duplicated entries function public.record(x, t) - if type(t) == "number" and last_t == t then - return - end + if util.is_num(t) and last_t == t then return end data[index] = x last_t = t @@ -202,61 +214,62 @@ end --#region TYPES +-- for speed +local b_str, n_str, s_str, t_str, f_str = "boolean", "number", "string", "table", "function" + -- is a value a boolean ---@nodiscard ---@param x any value ---@return boolean is_boolean -function util.is_bool(x) return type(x) == "boolean" end +function util.is_bool(x) return type(x) == b_str end -- is a value a number ---@nodiscard ---@param x any value ---@return boolean is_number -function util.is_num(x) return type(x) == "number" end +function util.is_num(x) return type(x) == n_str end -- is a value an integer ---@nodiscard ---@param x any value ---@return boolean is_integer -function util.is_int(x) return type(x) == "number" and x == math.floor(x) end +function util.is_int(x) return type(x) == n_str and x == math.floor(x) end -- is a value a string ---@nodiscard ---@param x any value ---@return boolean is_string -function util.is_str(x) return type(x) == "string" end +function util.is_str(x) return type(x) == s_str end -- is a value a table ---@nodiscard ---@param x any value ---@return boolean is_table -function util.is_tbl(x) return type(x) == "table" end +function util.is_tbl(x) return type(x) == t_str end -- is a value a function ---@nodiscard ---@param x any value ---@return boolean is_function -function util.is_func(x) return type(x) == "function" end +function util.is_func(x) return type(x) == f_str end --#endregion --#region TIME +local t_l = "local" + -- current time ---@nodiscard ---@return integer milliseconds -function util.time_ms() ---@diagnostic disable-next-line: undefined-field - return os.epoch('local') -end +function util.time_ms() return os.epoch(t_l) end -- current time ---@nodiscard ---@return number seconds -function util.time_s() ---@diagnostic disable-next-line: undefined-field - return os.epoch('local') / 1000.0 -end +function util.time_s() return os.epoch(t_l) / 1000.0 end -- current time ---@nodiscard @@ -271,10 +284,8 @@ function util.time() return util.time_ms() end ---@nodiscard ---@param target_event? string event to wait for ---@return os_event event, any param1, any param2, any param3, any param4, any param5 -function util.pull_event(target_event) ---@diagnostic disable-next-line: undefined-field - return os.pullEventRaw(target_event) -end +function util.pull_event(target_event) return os.pullEventRaw(target_event) end -- OS queue event raw wrapper with types ---@param event os_event @@ -292,17 +303,13 @@ end ---@nodiscard ---@param t number timer duration in seconds ---@return integer timer ID -function util.start_timer(t) ---@diagnostic disable-next-line: undefined-field - return os.startTimer(t) -end +function util.start_timer(t) return os.startTimer(t) end -- cancel an OS timer ---@param timer integer timer ID -function util.cancel_timer(timer) ---@diagnostic disable-next-line: undefined-field - os.cancelTimer(timer) -end +function util.cancel_timer(timer) os.cancelTimer(timer) end --#endregion @@ -311,10 +318,8 @@ end -- protected sleep call so we still are in charge of catching termination ---@param t integer seconds --- EVENT_CONSUMER: this function consumes events -function util.psleep(t) ---@diagnostic disable-next-line: undefined-field - pcall(os.sleep, t) -end +function util.psleep(t) pcall(os.sleep, t) end -- no-op to provide a brief pause (1 tick) to yield
--- EVENT_CONSUMER: this function consumes events @@ -405,8 +410,7 @@ local function ZFE(fe) return fe / 1000000000000000000000.0 end -- how & why did ---@param format? string format override ---@return string str, string? unit function util.power_format(fe, combine_label, format) - local unit - local value + local unit, value if type(format) ~= "string" then format = "%.2f" end @@ -454,32 +458,25 @@ end ---@nodiscard ---@param timeout number timeout duration function util.new_watchdog(timeout) - local self = { - timeout = timeout, - wd_timer = util.start_timer(timeout) - } + local self = { timeout = timeout, wd_timer = util.start_timer(timeout) } ---@class watchdog local public = {} -- check if a timer is this watchdog ---@nodiscard - ---@param timer number timer event timer ID + ---@param timer number event timer ID function public.is_timer(timer) return self.wd_timer == timer end -- satiate the beast function public.feed() - if self.wd_timer ~= nil then - util.cancel_timer(self.wd_timer) - end + public.cancel() self.wd_timer = util.start_timer(self.timeout) end -- cancel the watchdog function public.cancel() - if self.wd_timer ~= nil then - util.cancel_timer(self.wd_timer) - end + if self.wd_timer ~= nil then util.cancel_timer(self.wd_timer) end end return public @@ -492,10 +489,7 @@ end ---@nodiscard ---@param period number clock period function util.new_clock(period) - local self = { - period = period, - timer = nil - } + local self = { period = period, timer = nil } ---@class clock local public = {}