File: AttributeContainer.swift

package info (click to toggle)
swiftlang 6.2.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,856,264 kB
  • sloc: cpp: 9,995,718; ansic: 2,234,019; asm: 1,092,167; python: 313,940; objc: 82,726; f90: 80,126; lisp: 38,373; pascal: 25,580; sh: 20,378; ml: 5,058; perl: 4,751; makefile: 4,725; awk: 3,535; javascript: 3,018; xml: 918; fortran: 664; cs: 573; ruby: 396
file content (137 lines) | stat: -rw-r--r-- 5,400 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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2020-2023 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 the list of Swift project authors
//
//===----------------------------------------------------------------------===//

@dynamicMemberLookup
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
public struct AttributeContainer : Sendable {
    internal var storage : AttributedString._AttributeStorage
    
    public init() {
        storage = .init()
    }
    
    internal init(_ storage: AttributedString._AttributeStorage) {
        self.storage = storage
    }
}

@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
extension AttributeContainer {
    @preconcurrency
    public subscript<T: AttributedStringKey>(_: T.Type) -> T.Value? where T.Value : Sendable {
        get { storage[T.self] }
        set { storage[T.self] = newValue }
    }

    @preconcurrency
    @inlinable // Trivial implementation, allows callers to optimize away the keypath allocation
    public subscript<K: AttributedStringKey>(dynamicMember keyPath: KeyPath<AttributeDynamicLookup, K>) -> K.Value? where K.Value : Sendable {
        get { self[K.self] }
        set { self[K.self] = newValue }
    }

    public subscript<S: AttributeScope>(dynamicMember keyPath: KeyPath<AttributeScopes, S.Type>) -> ScopedAttributeContainer<S> {
        get {
            return ScopedAttributeContainer(storage)
        }
        _modify {
            var container = ScopedAttributeContainer<S>()
            defer {
                if let removedKey = container.removedKey {
                    storage[removedKey] = nil
                } else {
                    storage.mergeIn(container.storage)
                }
            }
            yield &container
        }
    }

    public static subscript<K: AttributedStringKey>(dynamicMember keyPath: KeyPath<AttributeDynamicLookup, K>) -> Builder<K> {
        return Builder(container: AttributeContainer())
    }

    @_disfavoredOverload
    public subscript<K: AttributedStringKey>(dynamicMember keyPath: KeyPath<AttributeDynamicLookup, K>) -> Builder<K> {
        return Builder(container: self)
    }

    public struct Builder<T: AttributedStringKey> : Sendable {
        var container : AttributeContainer

        @preconcurrency
        public func callAsFunction(_ value: T.Value) -> AttributeContainer where T.Value : Sendable {
            var new = container
            new[T.self] = value
            return new
        }
    }

    public mutating func merge(_ other: AttributeContainer, mergePolicy: AttributedString.AttributeMergePolicy = .keepNew) {
        self.storage.mergeIn(other.storage, mergePolicy: mergePolicy)
    }

    public func merging(_ other: AttributeContainer, mergePolicy:  AttributedString.AttributeMergePolicy = .keepNew) -> AttributeContainer {
        var copy = self
        copy.merge(other, mergePolicy:  mergePolicy)
        return copy
    }
}

@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
extension AttributeContainer: Equatable {}

@available(macOS 13, iOS 16, tvOS 16, watchOS 9, *)
extension AttributeContainer: Hashable {}

@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
extension AttributeContainer: CustomStringConvertible {
    public var description: String {
        storage.description
    }
}

extension AttributeContainer {
    internal var _hasConstrainedAttributes: Bool {
        storage.hasConstrainedAttributes
    }
}

@available(FoundationPreview 6.2, *)
extension AttributeContainer {
    /// Returns a copy of the attribute container with only attributes that specify the provided inheritance behavior.
    /// - Parameter inheritedByAddedText: An `inheritedByAddedText` value to filter. Attributes matching this value are included in the returned container.
    /// - Returns: A copy of the attribute container with only attributes whose `inheritedByAddedText` property matches the provided value.
    public func filter(inheritedByAddedText: Bool) -> AttributeContainer {
        var storage = self.storage
        for (key, value) in storage.contents {
            let inherited = value.inheritedByAddedText && !value.isInvalidatedOnTextChange
            if inherited != inheritedByAddedText {
                storage[key] = nil
            }
        }
        return AttributeContainer(storage)
    }
    
    /// Returns a copy of the attribute container with only attributes that have the provided run boundaries.
    /// - Parameter runBoundaries: The required `runBoundaries` value of the filtered attributes. If `nil` is provided, only attributes not bound to any specific boundary will be returned.
    /// - Returns: A copy of the attribute container with only attributes whose `runBoundaries` property matches the provided value.
    public func filter(runBoundaries: AttributedString.AttributeRunBoundaries?) -> AttributeContainer {
        var storage = self.storage
        for (key, value) in storage.contents {
            if value.runBoundaries != runBoundaries {
                storage[key] = nil
            }
        }
        return AttributeContainer(storage)
    }
}