@rbxts/evxryy-option 1.2.1 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/init.luau +355 -2
- package/package.json +1 -1
package/out/init.luau
CHANGED
|
@@ -1,2 +1,355 @@
|
|
|
1
|
-
--
|
|
2
|
-
|
|
1
|
+
--[[
|
|
2
|
+
author : evxry_ll
|
|
3
|
+
|
|
4
|
+
This module implements the Option type pattern, similar to Rust's Option<T>.
|
|
5
|
+
It provides a way to handle nullable values in a type-safe manner.
|
|
6
|
+
|
|
7
|
+
Option<T> can be either:
|
|
8
|
+
- Some(value): Contains a value of type T
|
|
9
|
+
- None: Contains no value
|
|
10
|
+
]]
|
|
11
|
+
|
|
12
|
+
-- Type aliases for better readability
|
|
13
|
+
type Some<T> = T
|
|
14
|
+
type SomeCallback<T,K> = (T) -> K
|
|
15
|
+
type None<T,K> = () -> K
|
|
16
|
+
|
|
17
|
+
-- Callback type definitions used throughout the module
|
|
18
|
+
type Callback<T> = () -> T -- Function that returns a value of type T
|
|
19
|
+
type FilterCallback<T> = (value : T) -> boolean -- Function that tests if a value meets criteria
|
|
20
|
+
type AndThenCallback<T, K> = (value : T) -> any -- Function that chains operations
|
|
21
|
+
|
|
22
|
+
-- Constructor table for creating Option instances
|
|
23
|
+
local OptionConstructor = {}
|
|
24
|
+
OptionConstructor.__index = OptionConstructor
|
|
25
|
+
|
|
26
|
+
-- Component table containing all Option methods
|
|
27
|
+
local OptionComponent = {}
|
|
28
|
+
OptionComponent.__index = OptionComponent
|
|
29
|
+
|
|
30
|
+
-- Export type definition for Option<T>
|
|
31
|
+
-- An Option can have either a "Some" tag with a value, or a "None" tag with nil
|
|
32
|
+
export type OptionComponent<T> = typeof(setmetatable({} :: {
|
|
33
|
+
Tag : "Some" | "None",
|
|
34
|
+
Some : T,
|
|
35
|
+
None : nil,
|
|
36
|
+
},OptionComponent))
|
|
37
|
+
|
|
38
|
+
--[[
|
|
39
|
+
Creates a Some variant of Option containing a value
|
|
40
|
+
@param SomeOption The value to wrap in Some
|
|
41
|
+
@return An Option containing the provided value
|
|
42
|
+
]]
|
|
43
|
+
function OptionConstructor.Some<SomeType>(SomeOption : Some<SomeType>) : OptionComponent<SomeType>
|
|
44
|
+
local self = setmetatable({
|
|
45
|
+
Some = SomeOption,
|
|
46
|
+
Tag = "Some",
|
|
47
|
+
},OptionComponent)
|
|
48
|
+
return self
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
--[[
|
|
52
|
+
Creates a None variant of Option containing no value
|
|
53
|
+
@return An empty Option
|
|
54
|
+
]]
|
|
55
|
+
function OptionConstructor.None() : OptionComponent<nil>
|
|
56
|
+
local self = setmetatable({
|
|
57
|
+
None = true,
|
|
58
|
+
Tag = "None"
|
|
59
|
+
},OptionComponent)
|
|
60
|
+
return self
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
--[[
|
|
64
|
+
Checks if a value is a valid Option instance
|
|
65
|
+
@param option The value to check
|
|
66
|
+
@return true if the value is an Option, false otherwise
|
|
67
|
+
]]
|
|
68
|
+
function OptionConstructor.IsOption<T>(option : OptionComponent<T>?)
|
|
69
|
+
if(option and option.Tag) then
|
|
70
|
+
return true
|
|
71
|
+
else
|
|
72
|
+
return false
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
--[[
|
|
77
|
+
Wraps a nullable value in an Option
|
|
78
|
+
If the value is nil, returns None; otherwise returns Some(value)
|
|
79
|
+
@param value The nullable value to wrap
|
|
80
|
+
@return Option<T> or Option<nil>
|
|
81
|
+
]]
|
|
82
|
+
function OptionConstructor.Wrap<T>(value : T?)
|
|
83
|
+
if(value ~= nil) then
|
|
84
|
+
return OptionConstructor.Some(value :: T) :: OptionComponent<T>
|
|
85
|
+
else
|
|
86
|
+
return OptionConstructor.None() :: OptionComponent<nil>
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
--[[
|
|
91
|
+
Deserializes data back into an Option
|
|
92
|
+
Used to reconstruct Options from stored/transmitted data
|
|
93
|
+
@param data Serialized Option data with Tag and Value fields
|
|
94
|
+
@return The reconstructed Option
|
|
95
|
+
]]
|
|
96
|
+
function OptionConstructor.Deserialize<T>(data : {Tag : "Some" | "None",Value : T})
|
|
97
|
+
return data.Value == nil and OptionConstructor.None() or OptionConstructor.Some(data.Value)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
--[[
|
|
101
|
+
Checks if this Option contains a value (is Some variant)
|
|
102
|
+
@return true if Option contains a value, false if None
|
|
103
|
+
]]
|
|
104
|
+
function OptionComponent.IsSome<T>(self : OptionComponent<T>)
|
|
105
|
+
return self.Tag == "Some" or self.Some ~= nil
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
--[[
|
|
109
|
+
Checks if this Option is empty (is None variant)
|
|
110
|
+
@return true if Option is None, false if it contains a value
|
|
111
|
+
]]
|
|
112
|
+
function OptionComponent.IsNone<T>(self : OptionComponent<T>)
|
|
113
|
+
return self.Tag == "None" or self.None ~= nil
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
--[[
|
|
117
|
+
Pattern matching for Option - executes different code based on variant
|
|
118
|
+
@param Options Table with Some and None callbacks
|
|
119
|
+
@return Result of the executed callback
|
|
120
|
+
]]
|
|
121
|
+
function OptionComponent.Match<T,K>(self : OptionComponent<T>,Options : {Some : SomeCallback<T,K>,None : None<T,K>}) : K
|
|
122
|
+
if(self:IsNone()) then
|
|
123
|
+
return Options.None() :: K
|
|
124
|
+
else
|
|
125
|
+
return Options.Some(self.Some) :: K
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
--[[
|
|
130
|
+
Asserts that the Option contains a value, throwing error if None
|
|
131
|
+
@param error_message Custom error message to display if assertion fails
|
|
132
|
+
]]
|
|
133
|
+
function OptionComponent.Assert<T>(self : OptionComponent<T>,error_message : string)
|
|
134
|
+
assert(self:IsSome(),error_message)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
--[[
|
|
138
|
+
Returns the contained value or a default if None
|
|
139
|
+
@param value Default value to return if Option is None
|
|
140
|
+
@return The contained value or the default
|
|
141
|
+
]]
|
|
142
|
+
function OptionComponent.GetOr<T, K>(self : OptionComponent<T>,value : K) : T | K
|
|
143
|
+
if(self:IsSome()) then
|
|
144
|
+
return self.Some :: T
|
|
145
|
+
else
|
|
146
|
+
return value
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
--[[
|
|
151
|
+
Transforms the contained value using a callback function
|
|
152
|
+
If None, returns None without calling the callback
|
|
153
|
+
@param callback Function to transform the value
|
|
154
|
+
@return New Option with transformed value or None
|
|
155
|
+
]]
|
|
156
|
+
function OptionComponent.Map<T,K>(self : OptionComponent<T>,callback : (value : T) -> K)
|
|
157
|
+
if(self:IsSome()) then
|
|
158
|
+
local outOption = callback(self.Some :: T)
|
|
159
|
+
return OptionConstructor.Some(outOption :: K) :: OptionComponent<K>
|
|
160
|
+
else
|
|
161
|
+
return OptionConstructor.None()
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
--[[
|
|
166
|
+
Filters the Option based on a predicate function
|
|
167
|
+
Returns None if the predicate returns false or if already None
|
|
168
|
+
@param callback Predicate function to test the value
|
|
169
|
+
@return Self if predicate passes, None otherwise
|
|
170
|
+
]]
|
|
171
|
+
function OptionComponent.Filter<T>(self : OptionComponent<T>,callback : FilterCallback<T>)
|
|
172
|
+
if(self:IsSome() and callback(self.Some :: T)) then
|
|
173
|
+
return self
|
|
174
|
+
else
|
|
175
|
+
return OptionConstructor.None()
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
--[[
|
|
180
|
+
Returns the contained value or computes a default using a callback
|
|
181
|
+
@param callback Function to compute default value if None
|
|
182
|
+
@return The contained value or computed default
|
|
183
|
+
]]
|
|
184
|
+
function OptionComponent.GetOrElse<T, K>(self : OptionComponent<T>,callback : Callback<K>) : T | K
|
|
185
|
+
if(self:IsSome()) then
|
|
186
|
+
return self.Some :: T
|
|
187
|
+
else
|
|
188
|
+
return callback() :: K
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
--[[
|
|
193
|
+
Exclusive OR operation between two Options
|
|
194
|
+
Returns Some if exactly one Option is Some, None if both are Some or both are None
|
|
195
|
+
@param OptionB The other Option to XOR with
|
|
196
|
+
@return Result of XOR operation
|
|
197
|
+
]]
|
|
198
|
+
function OptionComponent.XOR<T,K>(self : OptionComponent<T>,OptionB : OptionComponent<K>) : OptionComponent<T | K | nil>
|
|
199
|
+
local ValidOptionB = OptionConstructor.IsOption(OptionB)
|
|
200
|
+
if(not ValidOptionB) then return self :: OptionComponent<T> end
|
|
201
|
+
if(self:IsSome() and OptionB:IsSome()) then
|
|
202
|
+
return OptionConstructor.None() :: OptionComponent<nil>
|
|
203
|
+
elseif(self:IsSome()) then
|
|
204
|
+
return self :: OptionComponent<T>
|
|
205
|
+
else
|
|
206
|
+
return OptionB :: OptionComponent<K>
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
--[[
|
|
211
|
+
Chains Option operations - applies callback only if Some
|
|
212
|
+
The callback must return another Option
|
|
213
|
+
@param callback Function that takes the value and returns an Option
|
|
214
|
+
@return Result of the callback or None
|
|
215
|
+
]]
|
|
216
|
+
function OptionComponent.AndThen<T, K>(self : OptionComponent<T>,callback : (value : T) -> OptionComponent<K>)
|
|
217
|
+
if(self:IsSome()) then
|
|
218
|
+
local outOption = callback(self.Some :: T)
|
|
219
|
+
assert(OptionConstructor.IsOption(outOption),"current callback must return a OptionComponent.")
|
|
220
|
+
return outOption :: OptionComponent<K>
|
|
221
|
+
else
|
|
222
|
+
return OptionConstructor.None()
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
--[[
|
|
227
|
+
Unwraps the value with a custom panic message if None
|
|
228
|
+
@param msg Error message to display if Option is None
|
|
229
|
+
@return The contained value
|
|
230
|
+
@error Throws if Option is None
|
|
231
|
+
]]
|
|
232
|
+
function OptionComponent.Expect<T>(self : OptionComponent<T>,msg : string) : T
|
|
233
|
+
assert(self:IsSome(),msg)
|
|
234
|
+
return self.Some :: T
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
--[[
|
|
238
|
+
Asserts that the Option is None, throwing error if Some
|
|
239
|
+
@param msg Error message to display if Option contains a value
|
|
240
|
+
@error Throws if Option is Some
|
|
241
|
+
]]
|
|
242
|
+
function OptionComponent.ExpectNone<T>(self : OptionComponent<T>,msg : string)
|
|
243
|
+
assert(self:IsNone(),msg)
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
--[[
|
|
247
|
+
Unwraps the contained value, panicking with default message if None
|
|
248
|
+
@return The contained value
|
|
249
|
+
@error Throws "Called UnWrap() on None" if Option is None
|
|
250
|
+
]]
|
|
251
|
+
function OptionComponent.UnWrap<T>(self : OptionComponent<T>)
|
|
252
|
+
return self:Expect("Called UnWrap() on None")
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
--[[
|
|
256
|
+
Unwraps the value or returns a default if None
|
|
257
|
+
Alias for GetOr
|
|
258
|
+
@param value Default value to return if None
|
|
259
|
+
@return The contained value or default
|
|
260
|
+
]]
|
|
261
|
+
function OptionComponent.UnWrapOr<T, K>(self : OptionComponent<T>,value : K) : T | K
|
|
262
|
+
return self:GetOr(value)
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
--[[
|
|
266
|
+
Unwraps the value or computes a default if None
|
|
267
|
+
Alias for GetOrElse
|
|
268
|
+
@param callback Function to compute default if None
|
|
269
|
+
@return The contained value or computed default
|
|
270
|
+
]]
|
|
271
|
+
function OptionComponent.UnWrapOrElse<T, K>(self : OptionComponent<T>,callback : Callback<K>) : T | K
|
|
272
|
+
return self:GetOrElse(callback)
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
--[[
|
|
276
|
+
Checks if the Option contains a specific value
|
|
277
|
+
@param value The value to check for
|
|
278
|
+
@return true if Option contains the exact value, false otherwise
|
|
279
|
+
]]
|
|
280
|
+
function OptionComponent.Contains<T, K>(self : OptionComponent<T>,value : K)
|
|
281
|
+
return self:IsSome() and self.Some == value
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
--[[
|
|
285
|
+
String representation of the Option
|
|
286
|
+
@return "Option(value)" for Some, "Option(None)" for None
|
|
287
|
+
]]
|
|
288
|
+
function OptionComponent.__tostring<T>(self : OptionComponent<T>)
|
|
289
|
+
if(self:IsSome()) then
|
|
290
|
+
return "Option("..`{self.Some}`..")"
|
|
291
|
+
else
|
|
292
|
+
return "Option(None)"
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
--[[
|
|
297
|
+
Serializes the Option for storage or transmission
|
|
298
|
+
@return Table with Tag and optional Value fields
|
|
299
|
+
]]
|
|
300
|
+
function OptionComponent.Serialize<T>(self : OptionComponent<T>)
|
|
301
|
+
if(self:IsSome()) then
|
|
302
|
+
return {
|
|
303
|
+
Tag = self.Tag,
|
|
304
|
+
Value = self.Some :: T,
|
|
305
|
+
}
|
|
306
|
+
end
|
|
307
|
+
return {Tag = self.Tag}
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
--[[
|
|
311
|
+
Equality comparison between two Options
|
|
312
|
+
Two Options are equal if:
|
|
313
|
+
- Both are None, or
|
|
314
|
+
- Both are Some and contain equal values
|
|
315
|
+
@param b The other Option to compare with
|
|
316
|
+
@return true if Options are equal, false otherwise
|
|
317
|
+
]]
|
|
318
|
+
function OptionComponent.__eq<T>(self : OptionComponent<T>,b : OptionComponent<T>)
|
|
319
|
+
local aIsOption = OptionConstructor.IsOption(self)
|
|
320
|
+
local bIsOption = OptionConstructor.IsOption(b)
|
|
321
|
+
if(not aIsOption or not bIsOption) then return false end
|
|
322
|
+
if(self:IsSome() and b:IsSome()) then
|
|
323
|
+
return self.Some == b.Some
|
|
324
|
+
elseif(self:IsSome() and b:IsNone()) then
|
|
325
|
+
return false
|
|
326
|
+
elseif(self:IsNone() and b:IsNone()) then
|
|
327
|
+
return true
|
|
328
|
+
else
|
|
329
|
+
return false
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
-- Lowercase aliases for methods (alternative naming convention)
|
|
334
|
+
-- These provide the same functionality with camelCase naming
|
|
335
|
+
OptionComponent.Unwrap = OptionComponent.UnWrap
|
|
336
|
+
OptionComponent.UnwrapOr = OptionComponent.UnWrapOr
|
|
337
|
+
OptionComponent.getOr = OptionComponent.GetOr
|
|
338
|
+
OptionComponent.getOrElse = OptionComponent.GetOrElse
|
|
339
|
+
OptionComponent.expectNone = OptionComponent.ExpectNone
|
|
340
|
+
OptionComponent.andThen = OptionComponent.AndThen
|
|
341
|
+
OptionComponent.map = OptionComponent.Map
|
|
342
|
+
OptionComponent.filter = OptionComponent.Filter
|
|
343
|
+
OptionComponent.assert = OptionComponent.Assert
|
|
344
|
+
OptionComponent.match = OptionComponent.Match
|
|
345
|
+
OptionComponent.contains = OptionComponent.Contains
|
|
346
|
+
OptionComponent.isNone = OptionComponent.IsNone
|
|
347
|
+
OptionComponent.isSome = OptionComponent.IsSome
|
|
348
|
+
OptionComponent.serialize = OptionComponent.Serialize
|
|
349
|
+
|
|
350
|
+
-- OptionConstructor lowercase aliases
|
|
351
|
+
OptionConstructor.isOption = OptionConstructor.IsOption
|
|
352
|
+
OptionConstructor.deserialize = OptionConstructor.Deserialize
|
|
353
|
+
|
|
354
|
+
-- Export the constructor table to create Options
|
|
355
|
+
return OptionConstructor
|