2023-12-18 00:15:17 +11:00
|
|
|
lib.print.warn('ox_lib\'s class module is experimental and may break without warning.')
|
|
|
|
|
|
|
|
|
|
-- Fields added to the "private" field on a class will not be msgpacked.
|
|
|
|
|
-- Use setters/getters when working with these values.
|
|
|
|
|
local private_mt = {
|
|
|
|
|
__ext = 0,
|
|
|
|
|
__pack = function() return '' end,
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-19 14:32:07 +11:00
|
|
|
---Ensure the given argument or property has a valid type, otherwise throwing an error.
|
2023-12-18 11:17:48 +11:00
|
|
|
---@param id number | string
|
|
|
|
|
---@param var any
|
|
|
|
|
---@param expected type
|
|
|
|
|
local function assertType(id, var, expected)
|
|
|
|
|
local received = type(var)
|
|
|
|
|
|
|
|
|
|
if received ~= expected then
|
2024-03-12 16:09:13 +11:00
|
|
|
error(("expected %s %s to have type '%s' (received %s)")
|
|
|
|
|
:format(type(id) == 'string' and 'field' or 'argument', id, expected, received), 3)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if expected == 'table' and table.type(var) ~= 'hash' then
|
|
|
|
|
error(("expected argument %s to have table.type 'hash' (received %s)")
|
|
|
|
|
:format(id, table.type(var)), 3)
|
2023-12-18 11:17:48 +11:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
|
2024-03-11 09:06:36 +11:00
|
|
|
local mixins = {}
|
|
|
|
|
|
2023-12-19 14:32:07 +11:00
|
|
|
---Creates a new instance of the given class.
|
2024-03-12 16:10:57 +11:00
|
|
|
function mixins.new(class, ...)
|
|
|
|
|
local obj
|
|
|
|
|
|
|
|
|
|
if table.type(...) == 'hash' then
|
|
|
|
|
obj = ...
|
|
|
|
|
lib.print.warn(([[Creating instance of %s with a table and no constructor.
|
|
|
|
|
This behaviour is deprecated and will not be supported in the future.]])
|
|
|
|
|
:format(class.__name))
|
|
|
|
|
else
|
|
|
|
|
obj = {}
|
|
|
|
|
end
|
|
|
|
|
|
2023-12-18 00:15:17 +11:00
|
|
|
if obj.private then
|
2023-12-18 11:17:48 +11:00
|
|
|
assertType('private', obj.private, 'table')
|
2023-12-18 00:15:17 +11:00
|
|
|
setmetatable(obj.private, private_mt)
|
|
|
|
|
end
|
|
|
|
|
|
2023-12-19 14:32:07 +11:00
|
|
|
setmetatable(obj, class)
|
2023-12-18 00:15:17 +11:00
|
|
|
|
2024-03-12 16:10:57 +11:00
|
|
|
if class.constructor and obj ~= ... then
|
2024-03-11 14:58:54 +11:00
|
|
|
local parent = class
|
|
|
|
|
|
|
|
|
|
function obj:super(...)
|
|
|
|
|
parent = getmetatable(parent)
|
2024-03-12 16:10:57 +11:00
|
|
|
local constructor = parent and parent.constructor
|
2024-03-11 14:58:54 +11:00
|
|
|
|
2024-03-12 16:10:57 +11:00
|
|
|
if constructor then return constructor(self, ...) end
|
2024-03-11 14:58:54 +11:00
|
|
|
end
|
|
|
|
|
|
2024-03-12 16:10:57 +11:00
|
|
|
obj:constructor(...)
|
|
|
|
|
elseif class.init then
|
|
|
|
|
lib.print.warn(([[Calling %s:init() is deprecated and will not be supported in the future.
|
|
|
|
|
Use %s:constructor(...args) and assign properties in the constructor.]])
|
|
|
|
|
:format(class.__name, class.__name))
|
|
|
|
|
|
2024-03-11 14:58:54 +11:00
|
|
|
obj:init()
|
|
|
|
|
end
|
2023-12-18 00:15:17 +11:00
|
|
|
|
2024-03-12 16:10:57 +11:00
|
|
|
obj.super = nil
|
|
|
|
|
|
2023-12-18 00:15:17 +11:00
|
|
|
return obj
|
|
|
|
|
end
|
|
|
|
|
|
2024-03-11 09:06:58 +11:00
|
|
|
---Checks if an object is an instance of the given class.
|
2024-03-11 11:21:07 +11:00
|
|
|
function mixins.isClass(obj, class)
|
2024-03-11 09:06:58 +11:00
|
|
|
return getmetatable(obj) == class
|
|
|
|
|
end
|
|
|
|
|
|
2024-03-11 11:21:07 +11:00
|
|
|
---Checks if an object is an instance or derivative of the given class.
|
|
|
|
|
function mixins.instanceOf(obj, class)
|
|
|
|
|
local mt = getmetatable(obj)
|
|
|
|
|
|
|
|
|
|
while mt do
|
|
|
|
|
if mt == class then return true end
|
|
|
|
|
|
|
|
|
|
mt = getmetatable(mt)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
|
2023-12-19 14:32:07 +11:00
|
|
|
---Creates a new class.
|
2023-12-24 16:12:59 +11:00
|
|
|
---@todo add inherited types for new/private/init fields (not yet supported by lls)
|
2023-12-18 11:17:48 +11:00
|
|
|
---@param name string
|
2023-12-19 14:32:07 +11:00
|
|
|
---@param super? table
|
|
|
|
|
function lib.class(name, super)
|
2023-12-18 11:17:48 +11:00
|
|
|
assertType(1, name, 'string')
|
|
|
|
|
|
2024-03-11 09:06:36 +11:00
|
|
|
local class = table.clone(mixins)
|
2023-12-18 00:15:17 +11:00
|
|
|
|
2024-03-11 09:06:36 +11:00
|
|
|
class.__name = name
|
2023-12-19 14:32:07 +11:00
|
|
|
class.__index = class
|
|
|
|
|
|
2024-03-12 16:09:13 +11:00
|
|
|
if super then
|
|
|
|
|
assertType('super', super, 'table')
|
|
|
|
|
setmetatable(class, super)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
return class
|
2023-12-18 00:15:17 +11:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
return lib.class
|