Narrow aabb types and give generic aliases their type argument

The aabb functions all index the named members, so passing the
shorthand [MapPosition, MapPosition] form would error at runtime. The
annotations now say so.

emmylua requires a type argument on a generic alias, luals did not.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
bbassie
2026-08-07 15:31:18 +00:00
co-authored by Claude Opus 5
parent 90f32699c7
commit b9cfbc9036
6 changed files with 48 additions and 43 deletions
+6 -6
View File
@@ -84,7 +84,7 @@ local Commands = {
--- Contains the different status values a command can return
Commands.status = {}
--- @class (partial) Commands.types: table<string, Commands.InputParser | Commands.InputParserFactory>
--- @class (partial) Commands.types: table<string, Commands.InputParser<any> | Commands.InputParserFactory<any>>
--- Stores all input parsers and validators for different data types
Commands.types = {}
@@ -103,7 +103,7 @@ end
--- @class Commands.Argument
--- @field name string The name of the argument
--- @field description LocalisedString? The description of the argument
--- @field input_parser Commands.InputParser The input parser for the argument
--- @field input_parser Commands.InputParser<any> The input parser for the argument
--- @field optional boolean True when the argument is optional
--- @field default any? The default value of the argument
@@ -281,7 +281,7 @@ end
--- @alias Commands.InputParserFactory<T> fun(...: any): Commands.InputParser<T>
--- Add a new input parser to the command library, this method validates that it does not already exist
--- @generic T : Commands.InputParser | Commands.InputParserFactory
--- @generic T : Commands.InputParser<any> | Commands.InputParserFactory<any>
--- @param data_type string The name of the data type the input parser reads in and validates, becomes a key of Commands.types
--- @param input_parser T The function used to parse and validate the data type
--- @return T # The function which was provided as the second argument
@@ -295,7 +295,7 @@ function Commands.add_data_type(data_type, input_parser)
end
--- Remove an input parser for a data type, must be the same string that was passed to add_input_parser
--- @param data_type string | Commands.InputParser | Commands.InputParserFactory The data type or input parser you want to remove the input parser for
--- @param data_type string | Commands.InputParser<any> | Commands.InputParserFactory<any> The data type or input parser you want to remove the input parser for
function Commands.remove_data_type(data_type)
Commands.types[data_type] = nil
for k, v in pairs(Commands.types) do
@@ -433,7 +433,7 @@ end
--- Add a new required argument to the command of the given data type
--- @param name string The name of the argument being added
--- @param description LocalisedString? The description of the argument being added
--- @param input_parser Commands.InputParser The input parser to be used for the argument
--- @param input_parser Commands.InputParser<any> The input parser to be used for the argument
--- @return ExpCommand
function Commands._prototype:argument(name, description, input_parser)
assert_command_mutable(self)
@@ -454,7 +454,7 @@ end
--- Add a new optional argument to the command of the given data type
--- @param name string The name of the argument being added
--- @param description LocalisedString? The description of the argument being added
--- @param input_parser Commands.InputParser The input parser to be used for the argument
--- @param input_parser Commands.InputParser<any> The input parser to be used for the argument
--- @return ExpCommand
function Commands._prototype:optional(name, description, input_parser)
assert_command_mutable(self)
@@ -22,7 +22,7 @@ local min = math.min
--- @field trees LuaEntity[]
--- @field tree_count number
--- @field permission "fast" | "allow" | "disallow"
--- @field task Async.AsyncReturn
--- @field task Async.AsyncReturn<any>
local cache --- @type TreeDeconCache?
+2 -2
View File
@@ -6,7 +6,7 @@ local Async = require("modules/exp_util/async")
local Storage = require("modules/exp_util/storage")
local config = require("modules.exp_legacy.config.compilatron")
--- @type table<string, Async.AsyncReturn>
--- @type table<string, Async.AsyncReturn<any>>
local persistent_locations = {}
Storage.register(persistent_locations, function(tbl)
persistent_locations = tbl
@@ -55,7 +55,7 @@ local speech_bubble_task =
--- @param entity LuaEntity the entity which will have messages spawn from it
--- @param messages LocalisedString[] the messages which should be shown
--- @param starting_index number? the message index to start at, default 1
--- @return Async.AsyncReturn
--- @return Async.AsyncReturn<any>
local function register_entity(entity, messages, starting_index)
return speech_bubble_task{
entity = entity,
+23 -18
View File
@@ -7,26 +7,31 @@ local ceil = math.ceil
local min = math.min
local max = math.max
--- An axis aligned bounding box using named members, the shorthand form is not supported
--- @class ExpUtil_AABB.Box
--- @field left_top MapPosition.struct
--- @field right_bottom MapPosition.struct
--- @class ExpUtil_AABB
local AABB = {}
--- Check if an area is valid
--- @param aabb BoundingBox
--- @param aabb ExpUtil_AABB.Box
--- @return boolean # True if the area is valid
function AABB.valid(aabb)
return aabb.left_top.x < aabb.right_bottom.x and aabb.left_top.y < aabb.right_bottom.y
end
--- Returns the size of the area contained within an AABB
--- @param aabb BoundingBox
--- @param aabb ExpUtil_AABB.Box
--- @return number
function AABB.size(aabb)
return (aabb.right_bottom.x - aabb.left_top.x) * (aabb.right_bottom.y - aabb.left_top.y)
end
--- Clone an area, allows for safe mutation of an input value
--- @param aabb BoundingBox
--- @return BoundingBox
--- @param aabb ExpUtil_AABB.Box
--- @return ExpUtil_AABB.Box
function AABB.clone(aabb)
return {
left_top = { x = aabb.left_top.x, y = aabb.left_top.y },
@@ -35,8 +40,8 @@ function AABB.clone(aabb)
end
--- Expand an area to be integer aligned, expanding away from 0
--- @param aabb BoundingBox
--- @return BoundingBox
--- @param aabb ExpUtil_AABB.Box
--- @return ExpUtil_AABB.Box
function AABB.expand(aabb)
return {
left_top = { x = floor(aabb.left_top.x), y = floor(aabb.left_top.y) },
@@ -45,8 +50,8 @@ function AABB.expand(aabb)
end
--- Contract an area to be integer aligned, contracting towards 0
--- @param aabb BoundingBox
--- @return BoundingBox
--- @param aabb ExpUtil_AABB.Box
--- @return ExpUtil_AABB.Box
function AABB.contract(aabb)
return {
left_top = { x = ceil(aabb.left_top.x), y = ceil(aabb.left_top.y) },
@@ -55,9 +60,9 @@ function AABB.contract(aabb)
end
--- Expand an area to include all other areas
--- @param aabb BoundingBox
--- @param ... BoundingBox
--- @return BoundingBox
--- @param aabb ExpUtil_AABB.Box
--- @param ... ExpUtil_AABB.Box
--- @return ExpUtil_AABB.Box
function AABB.union(aabb, ...)
local rtn = AABB.clone(aabb)
for _, next_aabb in ipairs{ ... } do
@@ -70,9 +75,9 @@ function AABB.union(aabb, ...)
end
--- Contract an area to include to the overlap of all areas
--- @param aabb BoundingBox
--- @param ... BoundingBox
--- @return BoundingBox? # Nil if there is no intersection
--- @param aabb ExpUtil_AABB.Box
--- @param ... ExpUtil_AABB.Box
--- @return ExpUtil_AABB.Box? # Nil if there is no intersection
function AABB.intersect(aabb, ...)
local rtn = AABB.clone(aabb)
for _, next_aabb in ipairs{ ... } do
@@ -88,8 +93,8 @@ function AABB.intersect(aabb, ...)
end
--- Check if a point is contained within an area
--- @param aabb BoundingBox
--- @param point MapPosition
--- @param aabb ExpUtil_AABB.Box
--- @param point MapPosition.struct
--- @return boolean # True if the point is within or on the edge of the bounding box
function AABB.contains_point(aabb, point)
return point.x >= aabb.left_top.x and point.y >= aabb.left_top.y
@@ -97,8 +102,8 @@ function AABB.contains_point(aabb, point)
end
--- Check if an area is fulling contained within another area
--- @param aabb BoundingBox
--- @param other BoundingBox
--- @param aabb ExpUtil_AABB.Box
--- @param other ExpUtil_AABB.Box
--- @return boolean # True if the point is within or on the edge of the bounding box
function AABB.contains_area(aabb, other)
return AABB.contains_point(aabb, other.left_top) and AABB.contains_point(aabb, other.right_bottom)
+15 -15
View File
@@ -94,7 +94,7 @@ Async.status = {}
--- @class Async.AsyncFunction
--- @field id number The id of this async function
--- @operator call: Async.AsyncReturn
--- @operator call: Async.AsyncReturn<any>
Async._function_prototype = {}
Async._function_metatable = {
@@ -123,20 +123,20 @@ script.register_metatable("AsyncReturn", Async._return_metatable)
--- Storage Variables
local resolve_next --- @type Async.AsyncReturn[] Stores a queue of async functions to be executed on the next tick
local resolve_queue --- @type Async.AsyncReturn[] Stores a queue of async functions to be executed on a later tick
local resolve_next --- @type Async.AsyncReturn<any>[] Stores a queue of async functions to be executed on the next tick
local resolve_queue --- @type Async.AsyncReturn<any>[] Stores a queue of async functions to be executed on a later tick
--- Insert an item into the priority queue
--- @param pending Async.AsyncReturn
--- @return Async.AsyncReturn
--- @param pending Async.AsyncReturn<any>
--- @return Async.AsyncReturn<any>
local function add_to_next_tick(pending)
resolve_next[#resolve_next + 1] = pending
return pending
end
--- Insert an item into the priority queue
--- @param pending Async.AsyncReturn
--- @return Async.AsyncReturn
--- @param pending Async.AsyncReturn<any>
--- @return Async.AsyncReturn<any>
local function add_to_resolve_queue(pending)
local tick = pending.tick
for index = #resolve_queue, 1, -1 do
@@ -191,7 +191,7 @@ end
--- Run an async function on the next tick, this is the default and can be used to bypass permission groups
--- @param ... any The arguments to call the function with
--- @return Async.AsyncReturn
--- @return Async.AsyncReturn<any>
function Async._function_prototype:start_soon(...)
assert(Async._registered[self.id], "Async function is not registered")
Async._queue_pressure[self.id] = Async._queue_pressure[self.id] + 1
@@ -204,7 +204,7 @@ end
--- Run an async function after the given number of ticks
--- @param ticks number The number of ticks to call the function after
--- @param ... any The arguments to call the function with
--- @return Async.AsyncReturn
--- @return Async.AsyncReturn<any>
function Async._function_prototype:start_after(ticks, ...)
ExpUtil.assert_argument_type(ticks, "number", 1, "ticks")
assert(ticks > 0, "Ticks must be a positive number")
@@ -219,7 +219,7 @@ end
--- Run an async function on the next tick if the function is not already queued, allows singleton task/thread behaviour
--- @param ... any The arguments to call the function with
--- @return Async.AsyncReturn | nil
--- @return Async.AsyncReturn<any> | nil
function Async._function_prototype:start_task(...)
assert(Async._registered[self.id], "Async function is not registered")
if Async._queue_pressure[self.id] > 0 then return end
@@ -228,7 +228,7 @@ end
--- Run an async function on this tick, then queue it based on its return value
--- @param ... any The arguments to call the function with
--- @return Async.AsyncReturn
--- @return Async.AsyncReturn<any>
function Async._function_prototype:start_now(...)
assert(Async._registered[self.id], "Async function is not registered")
local status, rtn1, rtn2 = Async._registered[self.id](...)
@@ -293,11 +293,11 @@ end
--- Status Returns.
--- @type Async.AsyncReturn[], Async.AsyncReturn[]
--- @type Async.AsyncReturn<any>[], Async.AsyncReturn<any>[]
local new_next, new_queue = {}, {} -- File scope to allow for reuse
--- Executes an async function and processes the return value
--- @param pending Async.AsyncReturn
--- @param pending Async.AsyncReturn<any>
--- @param tick number
local function exec(pending, tick)
local async_func = Async._registered[pending.func_id]
@@ -397,9 +397,9 @@ end
--- @package
function Async.on_init()
if storage.exp_async_next == nil then
--- @type Async.AsyncReturn[]
--- @type Async.AsyncReturn<any>[]
storage.exp_async_next = {}
--- @type Async.AsyncReturn[]
--- @type Async.AsyncReturn<any>[]
storage.exp_async_queue = {}
end
Async.on_load()
+1 -1
View File
@@ -23,7 +23,7 @@ local Selection = {
--- @field player_index number
--- @field selection Selection.Active
--- @type table<string, { [defines.events]: Selection.event_handler[] }>
--- @type table<string, { [defines.events]: Selection.event_handler<any>[] }>
_registered = {},
--- @package