quad/quad-base/src/Relate.luau
qwreey-agent-selene 205af32da4
tooling: 프로젝트 셋업 문서화 + wally→pesde 전환, M1 스캐폴딩 골격
pesde 워크스페이스 실제 설치·검증(패키지명 하이픈 금지, workspace 의존성
문법, per-package pesde.lock), init.luau의 @self require 규칙(Luau RFC
확인), 워크스페이스 의존성이 심볼릭 링크라 luau CLI의 require-by-string과
충돌하는 함정을 base/project-setup-plan.md로 정리. architecture.md
패키징 방식 절도 같이 정정. Relate.luau/New()-InitXxx 골격/mock 하네스는
이 구조를 실제로 검증하는 과정에서 나온 최소 스캐폴딩.

Co-authored-by: qwreey <me@qwreey.moe>
2026-08-19 14:01:07 +09:00

92 lines
2.2 KiB
Text

--[[
Relate — inst를 weak 키로 하는 범용 릴레이션 프리미티브.
`.claude/base/relate-plan.md` "API"/"실제 구조" 절 그대로 구현.
]]
export type Relate = {
SetStrong: (self: Relate, inst: any, key: any, value: any) -> (),
GetStrong: (self: Relate, inst: any, key: any) -> any?,
SetWeak: (self: Relate, inst: any, key: any, value: any) -> (),
GetWeak: (self: Relate, inst: any, key: any) -> any?,
}
type Bucket = {
StrongMap: { [any]: any }?,
WeakMap: { [any]: any }?,
}
-- 모든 WeakMap이 공유하는 단일 메타테이블 — 매번 새로 만들 이유가 없음
local WEAK_VALUE_MT = { __mode = "v" }
local RelateImpl = {}
RelateImpl.__index = RelateImpl
local function getBucket(self, inst: any): Bucket?
return self.buckets[inst]
end
local function getOrCreateBucket(self, inst: any): Bucket
local bucket = self.buckets[inst]
if bucket == nil then
bucket = {} :: Bucket
self.buckets[inst] = bucket
end
return bucket
end
function RelateImpl:SetStrong(inst: any, key: any, value: any)
local bucket = getOrCreateBucket(self, inst)
local strongMap = bucket.StrongMap
if strongMap == nil then
local newMap = {}
bucket.StrongMap = newMap
newMap[key] = value
return
end
strongMap[key] = value
end
function RelateImpl:GetStrong(inst: any, key: any): any?
local bucket = getBucket(self, inst)
if bucket == nil then
return nil
end
local strongMap = bucket.StrongMap
if strongMap == nil then
return nil
end
return strongMap[key]
end
function RelateImpl:SetWeak(inst: any, key: any, value: any)
local bucket = getOrCreateBucket(self, inst)
local weakMap = bucket.WeakMap
if weakMap == nil then
local newMap = setmetatable({}, WEAK_VALUE_MT)
bucket.WeakMap = newMap
newMap[key] = value
return
end
weakMap[key] = value
end
function RelateImpl:GetWeak(inst: any, key: any): any?
local bucket = getBucket(self, inst)
if bucket == nil then
return nil
end
local weakMap = bucket.WeakMap
if weakMap == nil then
return nil
end
return weakMap[key]
end
local function Relate(): Relate
local self = setmetatable({
buckets = setmetatable({}, { __mode = "k" }) :: { [any]: Bucket },
}, RelateImpl)
return (self :: any) :: Relate
end
return Relate