File: DirectiveIndex.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (115 lines) | stat: -rw-r--r-- 4,300 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
 This source file is part of the Swift.org open source project

 Copyright (c) 2022 Apple Inc. and the Swift project authors
 Licensed under Apache License v2.0 with Runtime Library Exception

 See https://swift.org/LICENSE.txt for license information
 See https://swift.org/CONTRIBUTORS.txt for Swift project authors
*/

import Foundation

struct DirectiveIndex {
    static let topLevelReferenceDirectives: [AutomaticDirectiveConvertible.Type] = [
        Metadata.self,
        Redirect.self,
        Snippet.self,
        DeprecationSummary.self,
        Row.self,
        Options.self,
        Small.self,
        TabNavigator.self,
        Links.self,
        ImageMedia.self,
        VideoMedia.self,
    ]
    
    static let topLevelTutorialDirectives: [AutomaticDirectiveConvertible.Type] = [
        Tutorial.self,
    ]
    
    /// Children of tutorial directives that have not yet been converted to be automatically
    /// convertible.
    ///
    /// This is a temporary workaround until the migration is complete and these child directives
    /// can be automatically reflected from their parent directives.
    private static let otherTutorialDirectives: [AutomaticDirectiveConvertible.Type] = [
        Stack.self,
        Chapter.self,
        Choice.self,
    ]
    
    private static var allTopLevelDirectives = topLevelTutorialDirectives
        + topLevelReferenceDirectives
        + otherTutorialDirectives
    
    let indexedDirectives: [String : DirectiveMirror.ReflectedDirective]
    
    let renderableDirectives: [String : AnyRenderableDirectiveConvertibleType]
    
    static let shared = DirectiveIndex()
    
    private init() {
        // Pre-populate the directory index by iterating through the explicitly declared
        // top-level directives, finding their children and reflecting those as well.
        
        var indexedDirectives = [String : DirectiveMirror.ReflectedDirective]()
        
        for directive in Self.allTopLevelDirectives {
            let mirror = DirectiveMirror(reflecting: directive).reflectedDirective
            indexedDirectives[mirror.name] = mirror
        }
        
        var foundDirectives = indexedDirectives.values.flatMap(\.childDirectives).map(\.type)
        
        while !foundDirectives.isEmpty {
            let directive = foundDirectives.removeFirst()
            
            guard !indexedDirectives.keys.contains(directive.directiveName) else {
                continue
            }
            
            guard let automaticDirectiveConvertible = directive as? AutomaticDirectiveConvertible.Type else {
                continue
            }
            
            let mirror = DirectiveMirror(reflecting: automaticDirectiveConvertible).reflectedDirective
            indexedDirectives[mirror.name] = mirror
            
            for childDirective in mirror.childDirectives.map(\.type) {
                guard !indexedDirectives.keys.contains(childDirective.directiveName) else {
                    continue
                }
                
                foundDirectives.append(childDirective)
            }
        }
        
        self.indexedDirectives = indexedDirectives
        
        self.renderableDirectives = indexedDirectives.compactMapValues { directive in
            guard let renderableDirective = directive.type as? RenderableDirectiveConvertible.Type else {
                return nil
            }
            
            return AnyRenderableDirectiveConvertibleType(underlyingType: renderableDirective)
        }
    }
    
    func reflection(
        of directiveConvertible: AutomaticDirectiveConvertible.Type
    ) -> DirectiveMirror.ReflectedDirective {
        // It's a programmer error if an automatic directive convertible
        // is not in the pre-populated index.
        return indexedDirectives[directiveConvertible.directiveName]!
    }
    
    func reflection(of implementationName: String) -> DirectiveMirror.ReflectedDirective? {
        return indexedDirectives.first(
            where: { (directiveName: String, reflectedDirective: DirectiveMirror.ReflectedDirective) in
                directiveName == implementationName || String(describing: reflectedDirective.type) == implementationName
            }
        )?.value
    }
}