Last active
September 29, 2020 01:39
-
-
Save Anaminus/2c161f9e4b8145b3efdb3ffa3c360c4d to your computer and use it in GitHub Desktop.
Lightweight interfaces.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| local Impl | |
| local Is | |
| local Interface | |
| do | |
| local implementedInterfaces = setmetatable({}, {__mode="k"}) | |
| local embeddedInterfaces = {} | |
| local nillableInterfaces = {} | |
| -- Impl declares a value to implement zero or more interfaces, which must be | |
| -- strings. A value can be declared only once, and subsequent attempts do | |
| -- nothing. Impl returns the value. | |
| -- | |
| -- If an interface string has been declared previously with Interface, then | |
| -- the value will automatically implement any embedded interfaces. | |
| -- | |
| -- When Impl is called with a value and no interfaces, the value is said to | |
| -- "implement nothing". A value that has not been called with Impl is said | |
| -- to "not implement". | |
| function Impl(value, ...) | |
| if implementedInterfaces[value] then | |
| return value | |
| end | |
| if value == nil then | |
| return nil | |
| end | |
| local interfaces = {} | |
| implementedInterfaces[value] = interfaces | |
| local args = {...} | |
| for i = 1, #args do | |
| local interface = args[i] | |
| if type(interface) == "string" then | |
| interfaces[interface] = true | |
| local embedded = embeddedInterfaces[interface] | |
| if embedded then | |
| for embed in pairs(embedded) do | |
| interfaces[embed] = true | |
| end | |
| end | |
| end | |
| end | |
| return value | |
| end | |
| -- Is returns whether value v implements interface I. If v is nil, then Is | |
| -- returns true if the interface is nullable. If I is nil, then Is returns | |
| -- whether v implements. | |
| function Is(v, I) | |
| local interfaces = implementedInterfaces[v] | |
| if interfaces then | |
| if I == nil or interfaces[I] then | |
| return true | |
| end | |
| end | |
| if v == nil and nillableInterfaces[I] then | |
| return true | |
| end | |
| -- TODO: If v is a string, check if it is an interface that embeds I. | |
| return false | |
| end | |
| local declaredInterfaces = {} | |
| -- Interface declares and describes an interface. The first argument is the | |
| -- interface string, and each remaining argument is a string describing a | |
| -- behavior of the interface. An interface can be declared only once. | |
| -- | |
| -- If a behavior string matches an interface string declared previously, | |
| -- then that previous interface is embedded into the current interface. | |
| -- | |
| -- If a behavior is a nil value rather than a string, then this makes the | |
| -- interface "nullable", effectively causing nil to implement the interface. | |
| -- This behavior is inherited from embedded interfaces. | |
| function Interface(interface, ...) | |
| if declaredInterfaces[interface] then | |
| return | |
| end | |
| if type(interface) ~= "string" then | |
| return | |
| end | |
| local embedded = {} | |
| local behaviors = {} | |
| local notnull = true | |
| local args = {...} | |
| for i = 1, select("#", ...) do | |
| local behavior = args[i] | |
| if type(behavior) == "string" then | |
| local subEmbedded = embeddedInterfaces[behavior] | |
| if subEmbedded then | |
| embedded[behavior] = true | |
| for embed in pairs(subEmbedded) do | |
| embedded[embed] = true | |
| end | |
| if nillableInterfaces[behavior] and notnull then | |
| notnull = false | |
| nillableInterfaces[interface] = true | |
| end | |
| behaviors[#behaviors+1] = behavior .. " <embedded>" | |
| else | |
| behaviors[#behaviors+1] = behavior | |
| end | |
| elseif behavior == nil and notnull then | |
| notnull = false | |
| nillableInterfaces[interface] = true | |
| behaviors[#behaviors+1] = "<nullable>" | |
| end | |
| end | |
| declaredInterfaces[interface] = behaviors | |
| embeddedInterfaces[interface] = embedded | |
| return | |
| end | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment