in Sources/SwiftDocC/Infrastructure/Symbol Graph/SymbolGraphLoader.swift [48:128]
mutating func loadAll() throws {
let loadingLock = Lock()
let decoder = JSONDecoder()
var loadedGraphs = [URL: SymbolKit.SymbolGraph]()
let graphLoader = GraphCollector()
var loadError: Error?
let bundle = self.bundle
let dataProvider = self.dataProvider
let loadGraphAtURL: (URL) -> Void = { symbolGraphURL in
// Bail out in case a symbol graph has already errored
guard loadError == nil else { return }
do {
// Load and decode a single symbol graph file
let data = try dataProvider.contentsOfURL(symbolGraphURL, in: bundle)
var symbolGraph: SymbolGraph
switch decodingStrategy {
case .concurrentlyAllFiles:
symbolGraph = try decoder.decode(SymbolGraph.self, from: data)
case .concurrentlyEachFileInBatches:
symbolGraph = try SymbolGraphConcurrentDecoder.decode(data)
}
if let firstSymbolLanguage = symbolGraph.symbols.first?.value.identifier.interfaceLanguage {
guard FeatureFlags.current.isExperimentalObjectiveCSupportEnabled
|| InterfaceLanguage.from(string: firstSymbolLanguage) == .swift
else {
return
}
}
// `moduleNameFor(_:at:)` is static because it's pure function.
let (moduleName, _) = Self.moduleNameFor(symbolGraph, at: symbolGraphURL)
// If the bundle provides availability defaults add symbol availability data.
self.addDefaultAvailability(to: &symbolGraph, moduleName: moduleName)
// Store the decoded graph in `loadedGraphs`
loadingLock.sync {
loadedGraphs[symbolGraphURL] = symbolGraph
graphLoader.mergeSymbolGraph(symbolGraph, at: symbolGraphURL)
}
} catch {
// If the symbol graph was invalid, store the error
loadingLock.sync { loadError = error }
}
}
// If we have symbol graph files for multiple platforms
// load and decode each one on a separate thread.
// This strategy benchmarks better when we have multiple
// "larger" symbol graphs.
#if os(macOS) || os(iOS)
if bundle.symbolGraphURLs.filter({ !$0.path.contains("@") }).count > 1 {
// There are multiple main symbol graphs, better parallelize all files decoding.
decodingStrategy = .concurrentlyAllFiles
}
#endif
switch decodingStrategy {
case .concurrentlyAllFiles:
// Concurrently load and decode all symbol graphs
bundle.symbolGraphURLs.concurrentPerform(block: loadGraphAtURL)
case .concurrentlyEachFileInBatches:
// Serially load and decode all symbol graphs, each one in concurrent batches.
bundle.symbolGraphURLs.forEach(loadGraphAtURL)
}
// In case any of the symbol graphs errors, re-throw the error.
// We will not process unexpected file formats.
if let loadError = loadError {
throw loadError
}
self.symbolGraphs = loadedGraphs
(self.unifiedGraphs, self.graphLocations) = graphLoader.finishLoading()
}