Skip to content

Commit 334041f

Browse files
johnliedtkeJohn LiedtkeHT154
authored
Add registerPklTypes(_:) to bypass O(N) type discovery on first load (#110)
* Add registerPklTypes(_:) to bypass O(N) type discovery on first load In large binaries, _initializeShared() scans every Swift type in the binary via pkls_enumerateTypes and checks protocol conformance for each. For a CLI with thousands of linked types but only ~50 Pkl types, this caused ~14s startup latency. The new API lets callers pre-register types and skip the scan entirely. Co-authored-by: Cursor <cursoragent@cursor.com> * Formatting --------- Co-authored-by: John Liedtke <john.liedtke@walmart.com> Co-authored-by: Jen Basch <jbasch@apple.com>
1 parent ddcc2e3 commit 334041f

File tree

1 file changed

+42
-2
lines changed

1 file changed

+42
-2
lines changed

Sources/PklSwift/TypeRegistry.swift

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//===----------------------------------------------------------------------===//
2-
// Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
2+
// Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
33
//
44
// Licensed under the Apache License, Version 2.0 (the "License");
55
// you may not use this file except in compliance with the License.
@@ -124,9 +124,49 @@ extension TypeRegistry {
124124
if let _shared {
125125
return _shared
126126
} else {
127-
// first tine we're accessing so we need to initialize it
127+
// first time we're accessing so we need to initialize it
128128
return TypeRegistry._initializeShared()
129129
}
130130
}
131131
}
132+
133+
static func _registerTypes(_ types: [any PklRegisteredType.Type]) {
134+
self._sharedLock.withLock {
135+
precondition(
136+
self._shared == nil,
137+
"registerPklTypes(_:) must be called before any Pkl modules are loaded"
138+
)
139+
var registry = TypeRegistry()
140+
for t in types {
141+
registry.register(identifier: t.registeredIdentifier) { decoder in
142+
try t.init(from: decoder)
143+
}
144+
}
145+
self._shared = registry
146+
}
147+
}
148+
}
149+
150+
/// Explicitly registers a set of ``PklRegisteredType`` conformers, bypassing
151+
/// the automatic O(N) type discovery that scans all Swift types in the binary.
152+
///
153+
/// In large binaries, the default type discovery must iterate all Swift types
154+
/// linked into the process to find ``PklRegisteredType`` conformers. For
155+
/// binaries with thousands of types, this can add several seconds of latency on
156+
/// the first Pkl module load.
157+
///
158+
/// Call this once, before any `loadFrom` call:
159+
///
160+
/// ```swift
161+
/// registerPklTypes([
162+
/// MyModule.ModuleImpl.self,
163+
/// AnotherModule.Module.self,
164+
/// ])
165+
/// ```
166+
///
167+
/// - Parameter types: All ``PklRegisteredType`` conformers your app will decode.
168+
/// Any Pkl type not included here will result in a decoding error if encountered.
169+
/// - Precondition: Must be called before any Pkl module is loaded.
170+
public func registerPklTypes(_ types: [any PklRegisteredType.Type]) {
171+
TypeRegistry._registerTypes(types)
132172
}

0 commit comments

Comments
 (0)