-
-
Notifications
You must be signed in to change notification settings - Fork 102
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
141 additions
and
24 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
--!strict | ||
--!nolint LocalUnused | ||
--!nolint LocalShadow | ||
local task = nil -- Disable usage of Roblox's task scheduler | ||
|
||
--[[ | ||
Abstraction layer between Fusion internals and external debuggers, allowing | ||
for deep introspection using function hooks. | ||
Unlike `External`, attaching a debugger is optional, and all debugger | ||
functions are expected to be infallible and non-blocking. | ||
]] | ||
|
||
local Package = script.Parent | ||
local Types = require(Package.Types) | ||
|
||
local currentProvider: Types.ExternalDebugger? = nil | ||
local lastUpdateStep = 0 | ||
|
||
local Debugger = {} | ||
|
||
--[[ | ||
Swaps to a new debugger. | ||
Returns the old debugger, so it can be used again later. | ||
]] | ||
function Debugger.setDebugger( | ||
newProvider: Types.ExternalDebugger? | ||
): Types.ExternalDebugger? | ||
local oldProvider = currentProvider | ||
if oldProvider ~= nil then | ||
oldProvider.stopDebugging() | ||
end | ||
currentProvider = newProvider | ||
if newProvider ~= nil then | ||
newProvider.startDebugging() | ||
end | ||
return oldProvider | ||
end | ||
|
||
--[[ | ||
Called at the earliest moment after a scope is created or removed from the | ||
scope pool, but not before the scope has finished being prepared by the | ||
library, so that debuggers can register its existence and track changes | ||
to the scope over time. | ||
]] | ||
function Debugger.trackScope( | ||
scope: Types.Scope<unknown> | ||
): () | ||
if currentProvider == nil then | ||
return | ||
end | ||
currentProvider.trackScope(scope) | ||
end | ||
|
||
--[[ | ||
Called at the final moment before a scope is poisoned or added to the scope | ||
pool, after all cleanup tasks have completed, so that debuggers can erase | ||
the scope from internal trackers. Note that, due to scope pooling and user | ||
code, never assume that this correlates with garbage collection events. | ||
]] | ||
function Debugger.untrackScope( | ||
scope: Types.Scope<unknown> | ||
): () | ||
if currentProvider == nil then | ||
return | ||
end | ||
currentProvider.trackScope(scope) | ||
end | ||
|
||
return Debugger |
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
--!strict | ||
--!nolint LocalUnused | ||
--!nolint LocalShadow | ||
local task = nil -- Disable usage of Roblox's task scheduler | ||
|
||
--[[ | ||
Creates an empty scope with the same metatables as the original scope. Used | ||
for preserving access to constructors when creating inner scopes. | ||
This is the internal version of the function, which does not implement | ||
external debugging hooks. | ||
]] | ||
local Package = script.Parent.Parent | ||
local Types = require(Package.Types) | ||
local merge = require(Package.Utility.merge) | ||
local scopePool = require(Package.Memory.scopePool) | ||
|
||
-- This return type is technically a lie, but it's required for useful type | ||
-- checking behaviour. | ||
local function deriveScopeImpl<T>( | ||
existing: Types.Scope<T>, | ||
methods: {[unknown]: unknown}?, | ||
...: {[unknown]: unknown} | ||
): any | ||
local metatable = getmetatable(existing) | ||
if methods ~= nil then | ||
metatable = table.clone(metatable) | ||
metatable.__index = merge("first", table.clone(metatable.__index), methods, ...) | ||
end | ||
local scope = setmetatable( | ||
scopePool.reuseAny() :: any or {}, | ||
metatable | ||
) | ||
return scope | ||
end | ||
|
||
return (deriveScopeImpl :: any) :: Types.DeriveScopeConstructor |
This file contains 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
This file contains 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
This file contains 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
This file contains 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