Skip to content

Commit d2d836a

Browse files
committed
deploy
0 parents  commit d2d836a

File tree

2 files changed

+207
-0
lines changed

2 files changed

+207
-0
lines changed

Enum.lua

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
local RBXEnum = Enum
2+
local EnumInstance = setmetatable({}, {__tostring = function() return 'Enum' end, __metatable = 'this metatable is locked', __newindex = function(self, key: string) error(("%q is read only"):format(tostring(self))) end, __index = function(self, key: string) error(('%s is not a valid member of %q'):format(key, tostring(self)), 2) end})
3+
4+
local RegisteredMember = {
5+
Enums = {},
6+
UniqueNames = {},
7+
RegisteredValues = {}
8+
}
9+
10+
local HASH_SCALE = script:GetAttribute('HashScale') or 16
11+
12+
local function isEnum (enum: Enum)
13+
if typeof (enum) == 'Enum' then
14+
return true
15+
end
16+
17+
if getmetatable(enum) == EnumInstance then
18+
return true
19+
end
20+
21+
return false
22+
end
23+
24+
local function isEnumItem (enumItem: EnumItem)
25+
if typeof(enumItem) == 'EnumItem' then
26+
return true
27+
end
28+
29+
if typeof(enumItem) == 'number' then
30+
local value
31+
local completed = pcall(function()
32+
value = GetEnumFromValue(enumItem)
33+
end)
34+
return completed == true and value ~= nil
35+
end
36+
37+
return false
38+
end
39+
40+
local function IsNumberic(key: any)
41+
return typeof(key) == 'number'
42+
end
43+
44+
local function HashString(name: string) : number
45+
local hash = 0
46+
for i = 1, #name do
47+
hash = hash + string.byte(name, i)
48+
end
49+
50+
return math.floor(hash * HASH_SCALE)
51+
end
52+
53+
local function newEnum <A> (enumName: string, enumItems: A)
54+
if RegisteredMember.UniqueNames[enumName] then
55+
error(('Enum %q is registered'):format(enumName), 2)
56+
end
57+
58+
local hash = HashString(enumName)
59+
60+
export type StringName = keyof<A>
61+
62+
local enum = {}
63+
local added_values = {}
64+
local value_to_hash = {}
65+
local InternalEnumItems = {}
66+
local max_hash = hash
67+
local value_name = {}
68+
local item_count = 0
69+
70+
function enum:GetEnumItems () : {StringName}
71+
return InternalEnumItems
72+
end
73+
74+
function enum:FromName (name: StringName) : number
75+
return self[name]
76+
end
77+
78+
function enum:FromValue (value: number) : number
79+
for key, hashValue in pairs(value_to_hash) do
80+
if key == value or hashValue == value then
81+
return hashValue
82+
end
83+
end
84+
85+
error(('%s is not a valid member of %q'):format(value, tostring(self)), 2)
86+
end
87+
88+
function enum:GetNameFromValue (value: number) : string
89+
local value = self:FromValue(value)
90+
if value then
91+
return value_name[value]
92+
end
93+
end
94+
95+
96+
97+
local Enum = setmetatable({}, {
98+
__index = function(self, key: string)
99+
local value = enum[key]
100+
if value == nil then
101+
error(('%s is not a valid member of %q'):format(key, tostring(self)), 2)
102+
end
103+
104+
return value
105+
end,
106+
107+
__newindex = function(self, key: string)
108+
local value = enum[key]
109+
if value ~= nil then
110+
error(('Unable to assign property %s. Property is read only'):format(key), 2)
111+
end
112+
113+
error(('%s is not a valid member of %q'):format(key, tostring(self)), 2)
114+
end,
115+
116+
__tostring = function()
117+
return enumName
118+
end,
119+
120+
__len = function()
121+
return item_count
122+
end,
123+
124+
__metatable = EnumInstance
125+
})
126+
127+
128+
export type Enum = typeof(enum)
129+
130+
local idx = 0
131+
local max = math.floor(hash / HASH_SCALE) - 1
132+
133+
for key, value in pairs(enumItems) do
134+
local name = key
135+
local enumValue = idx + 1
136+
if IsNumberic(key) then
137+
name = value
138+
else
139+
if value > 0 then
140+
141+
if value > max then
142+
error(('%s: %q value is out of range. It should be between 1 and %d'):format(enumName, name, max), 2)
143+
end
144+
enumValue = math.clamp(value, 1, max)
145+
end
146+
end
147+
148+
if InternalEnumItems[name] then
149+
warn(('EnumItem %q is a duplicate and will be ignored for %q'):format(name, enumName), 2)
150+
continue
151+
end
152+
153+
while added_values[enumValue] and enumValue <= max do
154+
enumValue += 1
155+
end
156+
157+
added_values[enumValue] = true
158+
max_hash = (hash + enumValue) - 1
159+
enum[name] = max_hash
160+
161+
if RegisteredMember.RegisteredValues[max_hash] then
162+
error(('%s: EnumItem %q hash is already registered by another EnumItem'):format(enumName, name), 2)
163+
end
164+
165+
value_to_hash[enumValue] = max_hash
166+
RegisteredMember.RegisteredValues[max_hash] = Enum
167+
table.insert(InternalEnumItems, name)
168+
item_count += 1
169+
170+
value_name[max_hash] = name
171+
value_name[enumValue] = name
172+
173+
idx = enumValue
174+
end
175+
176+
177+
table.insert(RegisteredMember.Enums, Enum)
178+
RegisteredMember.UniqueNames[enumName] = true
179+
180+
return Enum :: Enum & A
181+
end
182+
183+
local Def = {}
184+
export type Enum = typeof(newEnum("Enum", Def))
185+
186+
187+
function GetRegisteredEnums () : {[number]: Enum}
188+
return RegisteredMember.Enums
189+
end
190+
191+
function GetEnumFromValue (value: number) : Enum
192+
local Enum = RegisteredMember.RegisteredValues[value]
193+
if Enum == nil then
194+
error(('%s is not a registered member of Enum'):format(value), 2)
195+
end
196+
197+
return Enum
198+
end
199+
200+
return {
201+
new = newEnum,
202+
isEnum = isEnum,
203+
isEnumItem = isEnumItem,
204+
RBXEnum = RBXEnum,
205+
getEnumFromValue = GetEnumFromValue,
206+
getRegisteredEnums = GetRegisteredEnums
207+
}

Enum.rbxm

2.91 KB
Binary file not shown.

0 commit comments

Comments
 (0)