quad/quad-base/src/Brand.luau
qwreey-agent-selene 89e078b387
docs: round11 파일 개명 — m2-implementation-round11* + 명명 규약 확정, M2 종결
- pre-implementation-handtrace-round11(.md/-brief.md) → m2-implementation-round11*
  (사용자: 구현 중 문서라 pre-implementation이 안 맞음), 인용처 22곳 일괄 치환
- 명명 규약(사용자 확정, README qa-request/ 행): mN-implementation-roundNN —
  라운드 번호는 마일스톤을 가로질러 단순 증가("m3 진행 중 m2 하자로 돌아가는
  경우도 있을 것"), 마일스톤 접두가 소속을 담음. round1~10 옛 이름은 실제로
  구현 전 라운드라 유지
- CLAUDE.md/project-context.md 머리말: M0~M2 완료, 다음은 M3(디스패치 엔진);
  todos 00 종결 표기 — 다음 액션은 M3 착수 규약 문항(사용자와 정할 것)

Co-authored-by: qwreey <me@qwreey.moe>
Claude-Session: https://claude.ai/code/session_01LF78pXeFGD1ZSVD3ifteYG
2026-08-31 13:40:27 +09:00

136 lines
4.1 KiB
Text

--[[
Brand — instance brands, one weak-key set per brand.
`.claude/base/brand-plan.md` "구현 — 인스턴스 브랜드" / "`isX` wrapper" sections,
as-is.
`Brand()` makes one brand object holding a weak-key member set; a value
registers itself into the brand(s) it belongs to (multi-tagging is the
point — `Source` is both `SourceBrand` and `EpochBrand`). There is no
reverse lookup (`Brand.get(x) -> tag` was reversed, see
`archive/brand-shared-registry-reversed.md`).
Every brand instance lives in this leaf file (M2 first-unit plan,
`qa-request/m2-implementation-round11-brief.md` §6): `EpochBrand`
is shared by `Source`/`Ref`/`GateNode`, so keeping the instances per type
module would force a circular require. Each *type* still registers only
into its own brand at its own construction sites; subtype relations are
expressed once, in the predicate (`isState`/`isRef` below), never by
double registration.
Method names are lowercase (`:register`/`:is`) on purpose — this is a
base-internal utility, not a public quad surface (`brand-plan.md`).
`Brand` depends on nothing. In particular there is no `None` special
case here — `isNone` is `v == None` and lives with `None.luau` (M3).
]]
export type Brand = {
register: (self: Brand, x: any) -> (),
is: (self: Brand, x: any) -> boolean,
}
local function Brand(): Brand
local members = setmetatable({}, { __mode = "k" }) :: { [any]: true }
return {
register = function(_self: Brand, x: any)
members[x] = true
end,
is = function(_self: Brand, x: any): boolean
return members[x] == true
end,
}
end
-- Each type owns exactly one brand. The full list is declared here even for
-- types that arrive in later milestones (`Tag`/`Attribute`/`Tween`/`Slot`)
-- so that the set of brands has one source; their `is*` predicates are added
-- with the type.
local ObserverBrand = Brand()
local EffectBrand = Brand()
local TagBrand = Brand()
local AttributeBrand = Brand()
local TweenBrand = Brand()
local BlockerBrand = Brand()
local StateBrand = Brand()
local SourceBrand = Brand()
local StoreBrand = Brand()
local SlotBrand = Brand()
local RefBrand = Brand()
local PreRefBrand = Brand()
local PostRefBrand = Brand()
local ModifierBrand = Brand()
local EpochBrand = Brand()
-- Plain identity predicates.
local function isEpoch(x: any): boolean
return EpochBrand:is(x)
end
local function isSource(x: any): boolean
return SourceBrand:is(x)
end
local function isStore(x: any): boolean
return StoreBrand:is(x)
end
local function isObserver(x: any): boolean
return ObserverBrand:is(x)
end
local function isEffect(x: any): boolean
return EffectBrand:is(x)
end
local function isBlocker(x: any): boolean
return BlockerBrand:is(x)
end
local function isModifier(x: any): boolean
return ModifierBrand:is(x)
end
-- Subtype relations: the more specific predicate is defined first and the
-- wider one is composed on top of it, so the direction of inclusion is
-- visible in the code (`brand-plan.md`).
local function isState(x: any): boolean
return isSource(x) or StateBrand:is(x) -- Source structurally satisfies State
end
local function isPreRef(x: any): boolean
return PreRefBrand:is(x)
end
local function isPostRef(x: any): boolean
return PostRefBrand:is(x)
end
local function isRef(x: any): boolean
-- PreRef/PostRef reuse the Ref runtime = both are a kind of Ref.
-- They are exclusive siblings of each other.
return isPreRef(x) or isPostRef(x) or RefBrand:is(x)
end
return {
Brand = Brand,
ObserverBrand = ObserverBrand,
EffectBrand = EffectBrand,
TagBrand = TagBrand,
AttributeBrand = AttributeBrand,
TweenBrand = TweenBrand,
BlockerBrand = BlockerBrand,
StateBrand = StateBrand,
SourceBrand = SourceBrand,
StoreBrand = StoreBrand,
SlotBrand = SlotBrand,
RefBrand = RefBrand,
PreRefBrand = PreRefBrand,
PostRefBrand = PostRefBrand,
ModifierBrand = ModifierBrand,
EpochBrand = EpochBrand,
isEpoch = isEpoch,
isSource = isSource,
isState = isState,
isStore = isStore,
isObserver = isObserver,
isEffect = isEffect,
isBlocker = isBlocker,
isModifier = isModifier,
isRef = isRef,
isPreRef = isPreRef,
isPostRef = isPostRef,
}