Coverage Report

Created: 2026-03-26 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/swift-protobuf/Sources/SwiftProtobuf/ExtensionFieldValueSet.swift
Line
Count
Source
1
// Sources/SwiftProtobuf/ExtensionFieldValueSet.swift - Extension support
2
//
3
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
4
// Licensed under Apache License v2.0 with Runtime Library Exception
5
//
6
// See LICENSE.txt for license information:
7
// https://github.com/apple/swift-protobuf/blob/main/LICENSE.txt
8
//
9
// -----------------------------------------------------------------------------
10
///
11
/// A collection of extension field values on a particular object.
12
/// This is only used within messages to manage the values of extension fields;
13
/// it does not need to be very sophisticated.
14
///
15
// -----------------------------------------------------------------------------
16
17
public struct ExtensionFieldValueSet: Hashable, Sendable {
18
43.4M
    fileprivate var values = [Int: any AnyExtensionField]()
19
20
    public static func == (
21
        lhs: ExtensionFieldValueSet,
22
        rhs: ExtensionFieldValueSet
23
0
    ) -> Bool {
24
0
        guard lhs.values.count == rhs.values.count else {
25
0
            return false
26
0
        }
27
0
        for (index, l) in lhs.values {
28
0
            if let r = rhs.values[index] {
29
0
                if type(of: l) != type(of: r) {
30
0
                    return false
31
0
                }
32
0
                if !l.isEqual(other: r) {
33
0
                    return false
34
0
                }
35
0
            } else {
36
0
                return false
37
0
            }
38
0
        }
39
0
        return true
40
0
    }
41
42
43.4M
    public init() {}
43
44
0
    public func hash(into hasher: inout Hasher) {
45
0
        // AnyExtensionField is not Hashable, and the Self constraint that would
46
0
        // add breaks some of the uses of it; so the only choice is to manually
47
0
        // mix things in. However, one must remember to do things in an order
48
0
        // independent manner.
49
0
        var hash = 16_777_619
50
0
        for (fieldNumber, v) in values {
51
0
            var localHasher = hasher
52
0
            localHasher.combine(fieldNumber)
53
0
            v.hash(into: &localHasher)
54
0
            hash = hash &+ localHasher.finalize()
55
0
        }
56
0
        hasher.combine(hash)
57
0
    }
58
59
90.9M
    public func traverse<V: Visitor>(visitor: inout V, start: Int, end: Int) throws {
60
90.9M
        let validIndexes = values.keys.filter { $0 >= start && $0 < end }
61
90.9M
        for i in validIndexes.sorted() {
62
31.7M
            let value = values[i]!
63
31.7M
            try value.traverse(visitor: &visitor)
64
90.9M
        }
65
90.9M
    }
66
67
    public subscript(index: Int) -> (any AnyExtensionField)? {
68
2.05M
        get { values[index] }
69
0
        set { values[index] = newValue }
70
    }
71
72
    mutating func modify<ReturnType>(
73
        index: Int,
74
        _ modifier: (inout (any AnyExtensionField)?) throws -> ReturnType
75
83.3M
    ) rethrows -> ReturnType {
76
83.3M
        // This internal helper exists to invoke the _modify accessor on Dictionary for the given operation, which can avoid CoWs
77
83.3M
        // during the modification operation.
78
83.3M
        try modifier(&values[index])
79
83.2M
    }
80
81
5.85M
    public var isInitialized: Bool {
82
5.85M
        for (_, v) in values {
83
2.28M
            if !v.isInitialized {
84
0
                return false
85
2.28M
            }
86
5.85M
        }
87
5.85M
        return true
88
5.85M
    }
89
}