88import Configuration
99import DevFoundation
1010import OSLog
11+ import Synchronization
1112
1213/// Provides access to configuration values queried by a `ConfigVariable`.
1314///
@@ -39,7 +40,14 @@ import OSLog
3940///
4041/// The reader never throws. If resolution fails, it returns the variable’s default value and posts a
4142/// ``ConfigVariableAccessFailedEvent`` to the event bus.
42- public struct ConfigVariableReader {
43+ public final class ConfigVariableReader : Sendable {
44+ /// The mutable state of a ``ConfigVariableReader``, protected by a `Mutex`.
45+ private struct MutableState : Sendable {
46+ /// The variables that have been registered with the reader, keyed by their configuration key.
47+ var registeredVariables : [ ConfigKey : RegisteredConfigVariable ] = [ : ]
48+ }
49+
50+
4351 /// The access reporter that is used to report configuration access events.
4452 public let accessReporter : any AccessReporter
4553
@@ -54,8 +62,8 @@ public struct ConfigVariableReader {
5462 /// The event bus used to post diagnostic events like ``ConfigVariableDecodingFailedEvent``.
5563 public let eventBus : EventBus
5664
57- /// The variables that have been registered with this reader, keyed by their configuration key .
58- private( set ) var registeredVariables : [ ConfigKey : RegisteredConfigVariable ] = [ : ]
65+ /// The mutable state protected by a mutex .
66+ private let mutableState = Mutex ( MutableState ( ) )
5967
6068 /// The logger used for registration diagnostics.
6169 private static let logger = Logger ( subsystem: " DevConfiguration " , category: " ConfigVariableReader " )
@@ -68,7 +76,7 @@ public struct ConfigVariableReader {
6876 /// - Parameters:
6977 /// - providers: The configuration providers, queried in order until a value is found.
7078 /// - eventBus: The event bus that telemetry events are posted on.
71- public init ( providers: [ any ConfigProvider ] , eventBus: EventBus ) {
79+ public convenience init ( providers: [ any ConfigProvider ] , eventBus: EventBus ) {
7280 self . init (
7381 providers: providers,
7482 accessReporter: EventBusAccessReporter ( eventBus: eventBus) ,
@@ -91,6 +99,12 @@ public struct ConfigVariableReader {
9199 self . providers = providers
92100 self . eventBus = eventBus
93101 }
102+
103+
104+ /// The variables that have been registered with this reader, keyed by their configuration key.
105+ var registeredVariables : [ ConfigKey : RegisteredConfigVariable ] {
106+ mutableState. withLock { $0. registeredVariables }
107+ }
94108}
95109
96110
@@ -107,7 +121,7 @@ extension ConfigVariableReader {
107121 /// warning is logged, and an assertion failure is triggered.
108122 ///
109123 /// - Parameter variable: The configuration variable to register.
110- public mutating func register< Value> ( _ variable: ConfigVariable < Value > ) {
124+ public func register< Value> ( _ variable: ConfigVariable < Value > ) {
111125 let defaultContent : ConfigContent
112126 do {
113127 defaultContent = try variable. content. encode ( variable. defaultValue)
@@ -117,17 +131,19 @@ extension ConfigVariableReader {
117131 return
118132 }
119133
120- if registeredVariables [ variable. key] != nil {
121- assertionFailure ( " Config variable ' \( variable. key) ' is already registered " )
122- Self . logger. error ( " Config variable ' \( variable. key) ' is already registered; overwriting " )
123- }
134+ mutableState. withLock { state in
135+ if state. registeredVariables [ variable. key] != nil {
136+ assertionFailure ( " Config variable ' \( variable. key) ' is already registered " )
137+ Self . logger. error ( " Config variable ' \( variable. key) ' is already registered; overwriting " )
138+ }
124139
125- registeredVariables [ variable. key] = RegisteredConfigVariable (
126- key: variable. key,
127- defaultContent: defaultContent,
128- secrecy: variable. secrecy,
129- metadata: variable. metadata
130- )
140+ state. registeredVariables [ variable. key] = RegisteredConfigVariable (
141+ key: variable. key,
142+ defaultContent: defaultContent,
143+ secrecy: variable. secrecy,
144+ metadata: variable. metadata
145+ )
146+ }
131147 }
132148}
133149
0 commit comments