SecuredMetatable
A lightweight metatable wrapper built for security and maintain proper code edicate among custom user objects and instances with built in protections and helpful features while still providing the full raw metatable api.
| Syntax | Result |
|---|---|
| RegularProperty | Denotes a Standard/Default property Anything that doesn't classify as something below. This is the default property that is read-only and must be manipulated with a special syntax see #page: |
| _PrivateProperty | Denotes a Private/Protected property 1 Underscore that cannot be indexed normally Object[Index]. Must be manipulated with a special syntax see #page: |
| __Metamethod | Denotes a Metamethod 2 Underscores. NOTE that some metamethods are assigned within the secured class and cannot be changed. IE: __index, __newindex, __metatable, These are static and cannot be changed |
| ___UnprotectedProperty | Denotes a Free/Unprotected property 3 Underscores. This property will have NO read or write protections. This is manipulable with regular table syntax |
Syntax Example
local T = {
["Test1"] = true, -- Creates a default property Read-Only
["_Protected"] = true, -- Creates a Protected property Internal only
["__Metamethod"] = "Test", -- Creates a Metamethod property must be a legal metamethod AND must be written in the metamethod table (THIS WILL ERROR)
["___UnProtected"] = "Test", -- Creates a Unprotected property without Read and Write restrictions
}
Types
WrappedMetatable
type WrappedMetatable = (T & MT & MM)Table, metatable, and metamethods all linked together, metamethods are private
structure
The Protected Metatable class is a read only wrapper that enacts a read only function apart of the __newindex metamethod, a sandboxed __index table, and the __metatable flag being enacted and is only destroyable by the :Destroy function.
Property index syntax
The Protected Metatable object has built in index syntax for different properties. First Both the Table and Metatable share these syntax. Such as: Protected, Metamethod, UnProtected, and standard syntax structures.
MetaMethods
interface MetaMethods {__index: ((self: T,index: (keyof(T) | any)) → () | {[any]: any})?,--
self[keyof(T)] Indexes the table attached (Not the actual Metatable)
__newindex: ((self: T,index: any,value: any) → () | {[any]: any})?,--
self[keyof(T)] = V Adds new value (locked for read only)
__call: ((self: T,...any) → any)?--
self() function call
__concat: ((self: T,value: V) → T & V)?,--
self..value Concatenation (combine)
__unm: ((self: T) → T)?,--
-self Unary (inverse)
__iter: (typeof(next))?,--
Generalized iteration (Type of next as default)
__add: ((self: T,value: number) → number)?,--
self+value Addition (Adds a number)
__sub: ((self: T,value: number) → number)?,--
self-value Subtraction (Subtracts a number)
__mul: ((self: T,value: number) → number)?,--
self*value Multiplication (Multiples a number)
__div: ((self: T,value: number) → number)?,--
self/value Division (Divides a number)
__idiv: ((self: T,value: number) → number)?,--
self//value Floor division (Floor divides a number)
__mod: ((self: T,value: number) → number)?,--
self%value Modulus (Modulo's by a number)
__pow: ((self: T,value: number) → number)?,--
self^value Exponentiation (Exponentiates a number)
__tostring: ((self: T) → string)?,--
tostring(self) -> printable string ()
__len: ((self: T) → number)?,--
#self Array length (length)
__eq: ((self: T,value: any) → boolean)?,--
self==value Equality operator (compares a value to be equal)
__lt: ((self: T,value: any) → boolean)?,--
self<value Less than operator (compares a value to be less than)
__le: ((self: T,value: any) → boolean)?,--
self<=value Less than or equal operator (compares a value to be less than or equal)
__mode: ("K" | "V" | "KV")?,--
Sets the garbage collection rule of the table
__metatable: string--
Locks metatable
__destroy: ((self: T,OptionalBooleanArgument:boolean) → ())?,--
custom function to be assigned when 'Destroy is called'
__typeKey: string?,--
The index needed to access the private and default metatable,
}A strongly typed metatable of all lua 5.1 metamethods + extras
Forbidden
Metamethods: __index, __newindex, and __metatable are custom and constant and cannot be written or read from. __tostring and __typeKey are the only exceptions, by default they are assigned to flag but are EDITABLE when writing the metamethod table.
Comparisons
__eq, __lt, __le Requires two values with the same metamethod function and basic type (table/userdata/etc.); does not work with a table and another random table, or with a userdata and a table.
New Metamethod
__destroy can be assigned to be ran before the auto cleanup of :Destroy(). __typeKey is a optional parameter default is Flag this is the index of the Metatable object when you want to access private and default variables ie: helper functions
Metamethods and their status
| Metamethod | Write Safety | Read Safety |
|---|---|---|
| __index | False | False |
| __newindex | False | False |
| __call | True | False |
| __concat | True | False |
| __unm | True | False |
| __add | True | False |
| __sub | True | False |
| __mul | True | False |
| __div | True | False |
| __idiv | True | False |
| __mod | True | False |
| __pow | True | False |
| __tostring | True | True |
| __metatable | False | True |
| __eq | True | False |
| __lt | True | False |
| __le | True | False |
| __mode | True | False |
| __len | True | False |
| __iter | True | False |
| __destroy | True | False |
| __typeKey | True | True |
Functions
NewMetatable
SecuredMetatable.NewMetatable(Table: T,--
The front table template and inital values
Metatable: MT,--
The metatable template and inital values
Flag: string,--
The string that is assigned to __metatable, __tostring, and __typeKey by default
) → WrappedMetatable--
A special securely wrapped metatable
Creates a new Wrapped Metatable object
Function
SecuredClasses returns a function that is called to create a WrappedMetatable class NOT a dictionary
local T = {
ClassName = "SecuredClass"
_PrivateData = 10,
}
local MT = {
GetPrivateData = function(self)
return self.Key._PrivateData
end
}
local MM:SecuredClasses.MetaMethods<typeof(T) & typeof(MT)> = {
__typeKey = "Key",
__destroy = function(self)
print("Destroyed", getmetatable(self)) -- Destroyed SecuredClass
end,
__tostring = function(self)
return `Class: {self.ClassName}`
end
}
local SecuredClass = SecuredClasses(T, MT, "SecuredClass", MM)
SecuredClass:GetPrivateData() -- 10
print(SecuredClass._PrivateData) -- Nil & Warn
Type union
Due to the nature of generics and the current state of type functions try and keep metamethods out of the Metatable or Table "Leaving them in will not break anything as they are sorted into their correct categories". As this can cause the type union to include non accessible type objects. And due to the experimental state of type functions there isnt a way to programmatically remove them without breaking something else.
Destroy
SecuredMetatable:Destroy(Nuke: boolean--
Complete destroy or optional boolean parameter for __destroy
) → nilThe only way to destroy the metatable when flags are assigned
-- Inherits properties from above
local SecuredClass = SecuredClasses(T, MT, "SecuredClass", MM)
SecuredClass:GetPrivateData() -- 10
print(SecuredClass, getmetatable(SecuredClass)) -- Class: SecuredClass, SecuredClass
SecuredClass:Destroy() -- Nil
print(SecuredClass, getmetatable(SecuredClass)) -- {}, Nil
SecuredClass:GetPrivateData() -- Attempt to index nil with GetPrivateData
Auto clean-up
Destroy contains a recursive cleaning function that is able to properly disable and deallocate all basic ROBLOX objects. The Nuke parameter is used when you want to call :Destroy on an instance ie: destroying a Basepart or Model. OR If you have a function binded to __destroy you can pass this optional boolean + more if applicable.
__destroy
The custom metamethod __destroy is a metamethod you can assign that will run BEFORE the auto clean-up. It is recommended to only use this metamethod to clean non default ROBLOX objects such as: Signals, Controllers, or user-Created classes then remove the index from the table. If you have a property that is a ROBLOX object such as: instances, threads, or RBXScriptConnections let the auto clean-up remove them instead.
Irreversible
Once :Destroy() is called this action cannot be undone and the metatable will be completely deallocated calling print(CLASS, getmetatable(CLASS)) will return { }, nil