Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 38 additions & 14 deletions src/rogue-properties/src/Shared/Array/RoguePropertyArrayUtils.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
--!nonstrict
--!strict
--[=[
@class RoguePropertyArrayUtils
]=]
Expand All @@ -7,6 +7,7 @@ local require = require(script.Parent.loader).load(script)

local DefaultValueUtils = require("DefaultValueUtils")
local RoguePropertyArrayConstants = require("RoguePropertyArrayConstants")
local RoguePropertyTypes = require("RoguePropertyTypes")
local String = require("String")

local RoguePropertyArrayUtils = {}
Expand All @@ -19,8 +20,14 @@ function RoguePropertyArrayUtils.getIndexFromName(name: string): number?
return tonumber(String.removePrefix(name, RoguePropertyArrayConstants.ARRAY_ENTRY_PERFIX))
end

function RoguePropertyArrayUtils.createRequiredPropertyDefinitionFromArray(arrayData, parentPropertyTableDefinition)
local expectedType = typeof(arrayData[1])
function RoguePropertyArrayUtils.createRequiredPropertyDefinitionFromArray(
arrayData: { any },
parentPropertyTableDefinition: RoguePropertyTypes.RoguePropertyDefinition
): (
RoguePropertyTypes.RoguePropertyDefinition?,
string?
)
local expectedType: string? = typeof(arrayData[1])
if expectedType == "table" then
return RoguePropertyArrayUtils.createRequiredTableDefinition(arrayData, parentPropertyTableDefinition)
elseif expectedType == "nil" then
Expand All @@ -31,14 +38,22 @@ function RoguePropertyArrayUtils.createRequiredPropertyDefinitionFromArray(array
if typeof(item) ~= expectedType then
expectedType = nil
-- TODO: Maybe union?
return nil, string.format("Expected type %q on %q, got %q", expectedType, tostring(index), typeof(item))
return nil,
string.format("Expected type %q on %q, got %q", expectedType :: any, tostring(index), typeof(item))
end
end

return RoguePropertyArrayUtils.createRequiredPropertyDefinitionFromType(expectedType, parentPropertyTableDefinition)
-- expectedType is only ever nil on a path that returns above, so it is a string here.
return RoguePropertyArrayUtils.createRequiredPropertyDefinitionFromType(
expectedType :: string,
parentPropertyTableDefinition
)
end

function RoguePropertyArrayUtils.createRequiredTableDefinition(arrayData, parentPropertyTableDefinition)
function RoguePropertyArrayUtils.createRequiredTableDefinition(
arrayData: { any },
parentPropertyTableDefinition: RoguePropertyTypes.RoguePropertyDefinition
): (RoguePropertyTypes.RoguePropertyDefinition?, string?)
local RoguePropertyTableDefinition = (require :: any)("RoguePropertyTableDefinition")

local entry = arrayData[1]
Expand All @@ -64,7 +79,10 @@ end

function RoguePropertyArrayUtils.createRequiredPropertyDefinitionFromType(
expectedType: string,
parentPropertyTableDefinition
parentPropertyTableDefinition: RoguePropertyTypes.RoguePropertyDefinition
): (
RoguePropertyTypes.RoguePropertyDefinition?,
string?
)
local RoguePropertyDefinition = (require :: any)("RoguePropertyDefinition")

Expand All @@ -81,7 +99,10 @@ function RoguePropertyArrayUtils.createRequiredPropertyDefinitionFromType(
return propertyDefinition
end

function RoguePropertyArrayUtils.createDefinitionsFromContainer(container: Instance, parentPropertyTableDefinition)
function RoguePropertyArrayUtils.createDefinitionsFromContainer(
container: Instance,
parentPropertyTableDefinition: RoguePropertyTypes.RoguePropertyDefinition
): { [number]: RoguePropertyTypes.RoguePropertyDefinition }
local RoguePropertyTableDefinition = (require :: any)("RoguePropertyTableDefinition")
local RoguePropertyDefinition = (require :: any)("RoguePropertyDefinition")

Expand All @@ -103,7 +124,7 @@ function RoguePropertyArrayUtils.createDefinitionsFromContainer(container: Insta
definition = RoguePropertyDefinition.new()
definition:SetName(item.Name)
definition:SetParentPropertyTableDefinition(parentPropertyTableDefinition)
definition:SetDefaultValue(item.Value)
definition:SetDefaultValue((item :: any).Value)
end

value[index] = definition
Expand All @@ -112,8 +133,8 @@ function RoguePropertyArrayUtils.createDefinitionsFromContainer(container: Insta
return value
end

function RoguePropertyArrayUtils.getDefaultValueMapFromContainer(container: Instance)
local value = {}
function RoguePropertyArrayUtils.getDefaultValueMapFromContainer(container: Instance): { [any]: any }
local value: { [any]: any } = {}

-- This is a hack, kinda
for attributeKey, attributeValue in container:GetAttributes() do
Expand All @@ -128,21 +149,24 @@ function RoguePropertyArrayUtils.getDefaultValueMapFromContainer(container: Inst
if item:IsA("Folder") then
value[index] = RoguePropertyArrayUtils.getDefaultValueMapFromContainer(item)
elseif item:IsA("ValueBase") then
value[index] = item.Value
value[index] = (item :: any).Value
end
else
if item:IsA("Folder") then
value[item.Name] = RoguePropertyArrayUtils.getDefaultValueMapFromContainer(item)
else
value[item.Name] = item.Value
value[item.Name] = (item :: any).Value
end
end
end

return value
end

function RoguePropertyArrayUtils.createDefinitionsFromArrayData(arrayData, propertyTableDefinition)
function RoguePropertyArrayUtils.createDefinitionsFromArrayData(
arrayData: { any },
propertyTableDefinition: RoguePropertyTypes.RoguePropertyDefinition
): { [number]: RoguePropertyTypes.RoguePropertyDefinition }
local RoguePropertyTableDefinition = (require :: any)("RoguePropertyTableDefinition")
local RoguePropertyDefinition = (require :: any)("RoguePropertyDefinition")

Expand Down
23 changes: 17 additions & 6 deletions src/rogue-properties/src/Shared/Cache/RoguePropertyCache.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
--!nonstrict
--!strict
--[=[
Utility class that helps cache rogue properties per an instance

Expand All @@ -11,11 +11,22 @@ local RoguePropertyCache = {}
RoguePropertyCache.ClassName = "RoguePropertyCache"
RoguePropertyCache.__index = RoguePropertyCache

function RoguePropertyCache.new(debugName: string)
local self = setmetatable({}, RoguePropertyCache)
-- A cached entry is either a RogueProperty or a RoguePropertyTable. Those types
-- form a require cycle with this module (Definition -> CacheService -> ... ->
-- Property/Table -> Definition), so the cache stores them structurally as `any`.
export type RoguePropertyCache = typeof(setmetatable(
{} :: {
_debugName: string,
_cache: { [Instance]: any },
},
{} :: typeof({ __index = RoguePropertyCache })
))

function RoguePropertyCache.new(debugName: string): RoguePropertyCache
local self: RoguePropertyCache = setmetatable({} :: any, RoguePropertyCache)

self._debugName = debugName
self._cache = setmetatable({}, WEAK_KV)
self._cache = setmetatable({}, WEAK_KV) :: any

return self
end
Expand All @@ -26,7 +37,7 @@ end
@param adornee Instance
@param roguePropertyTable RoguePropertyTable
]=]
function RoguePropertyCache:Store(adornee: Instance, roguePropertyTable)
function RoguePropertyCache.Store(self: RoguePropertyCache, adornee: Instance, roguePropertyTable: any)
assert(typeof(adornee) == "Instance", "Bad adornee")

self._cache[adornee] = roguePropertyTable
Expand All @@ -38,7 +49,7 @@ end
@param adornee Instance
@return RoguePropertyTable
]=]
function RoguePropertyCache:Find(adornee: Instance)
function RoguePropertyCache.Find(self: RoguePropertyCache, adornee: Instance): any
assert(typeof(adornee) == "Instance", "Bad adornee")

return self._cache[adornee]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
--!nonstrict
--!strict
--[=[
Constructing a new rogue property/rogue property table can be expensive.
This caches it so frame-usage is cheap.
Expand All @@ -10,21 +10,33 @@ local require = require(script.Parent.loader).load(script)
local RunService = game:GetService("RunService")

local RoguePropertyCache = require("RoguePropertyCache")
local RoguePropertyTypes = require("RoguePropertyTypes")
local ServiceBag = require("ServiceBag")

local RoguePropertyCacheService = {}
RoguePropertyCacheService.ServiceName = "RoguePropertyCacheService"

local WEAK_K_TABLE = { __mode = "k" }

function RoguePropertyCacheService:Init(serviceBag: ServiceBag.ServiceBag)
assert(not self._serviceBag, "Already initialized")
export type RoguePropertyCacheService = typeof(setmetatable(
{} :: {
_serviceBag: ServiceBag.ServiceBag,
_cache: { [RoguePropertyTypes.RoguePropertyDefinition]: RoguePropertyCache.RoguePropertyCache },
},
{} :: typeof({ __index = RoguePropertyCacheService })
))

function RoguePropertyCacheService.Init(self: RoguePropertyCacheService, serviceBag: ServiceBag.ServiceBag)
assert(not (self :: any)._serviceBag, "Already initialized")
self._serviceBag = assert(serviceBag, "No serviceBag")

self._cache = setmetatable({}, WEAK_K_TABLE)
self._cache = setmetatable({}, WEAK_K_TABLE) :: any
end

function RoguePropertyCacheService:GetCache(roguePropertyDefinition)
function RoguePropertyCacheService.GetCache(
self: RoguePropertyCacheService,
roguePropertyDefinition: RoguePropertyTypes.RoguePropertyDefinition
): RoguePropertyCache.RoguePropertyCache
if not self._cache then
assert(not RunService:IsRunning(), "Not in test mode")
-- Test mode
Expand Down
Loading
Loading