Coverage Report

Created: 2026-10-23 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/grpc-swift/Sources/GRPC/UserInfo.swift
Line
Count
Source
1
/*
2
 * Copyright 2020, gRPC Authors All rights reserved.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
/// ``UserInfo`` is a dictionary for heterogeneously typed values with type safe access to the stored
18
/// values.
19
///
20
/// ``UserInfo`` is shared between server interceptor contexts and server handlers, this is on a
21
/// per-RPC basis. ``UserInfo`` is *not* shared across a connection.
22
///
23
/// Values are keyed by a type conforming to the ``UserInfo/Key`` protocol. The protocol requires an
24
/// `associatedtype`: the type of the value the key is paired with. A key can be created using a
25
/// caseless `enum`, for example:
26
///
27
/// ```
28
/// enum IDKey: UserInfo.Key {
29
///   typealias Value = Int
30
/// }
31
/// ```
32
///
33
/// Values can be set and retrieved from ``UserInfo`` by subscripting with the key:
34
///
35
/// ```
36
/// userInfo[IDKey.self] = 42
37
/// let id = userInfo[IDKey.self]  // id = 42
38
///
39
/// userInfo[IDKey.self] = nil
40
/// ```
41
///
42
/// More convenient access can be provided with helper extensions on ``UserInfo``:
43
///
44
/// ```
45
/// extension UserInfo {
46
///   var id: IDKey.Value? {
47
///     get { self[IDKey.self] }
48
///     set { self[IDKey.self] = newValue }
49
///   }
50
/// }
51
/// ```
52
public struct UserInfo: CustomStringConvertible {
53
  private var storage: [AnyUserInfoKey: Any]
54
55
  /// A protocol for a key.
56
  public typealias Key = UserInfoKey
57
58
  /// Create an empty 'UserInfo'.
59
4.90M
  public init() {
60
4.90M
    self.storage = [:]
61
4.90M
  }
62
63
  /// Allows values to be set and retrieved in a type safe way.
64
  public subscript<Key: UserInfoKey>(key: Key.Type) -> Key.Value? {
65
0
    get {
66
0
      if let anyValue = self.storage[AnyUserInfoKey(key)] {
67
0
        // The types must line up here.
68
0
        return (anyValue as! Key.Value)
69
0
      } else {
70
0
        return nil
71
0
      }
72
0
    }
73
0
    set {
74
0
      self.storage[AnyUserInfoKey(key)] = newValue
75
0
    }
76
  }
77
78
0
  public var description: String {
79
0
    return "["
80
0
      + self.storage.map { key, value in
81
0
        "\(key): \(value)"
82
0
      }.joined(separator: ", ") + "]"
83
0
  }
84
85
  /// A `UserInfoKey` wrapper.
86
  private struct AnyUserInfoKey: Hashable, CustomStringConvertible {
87
    private let keyType: Any.Type
88
89
0
    var description: String {
90
0
      return String(describing: self.keyType.self)
91
0
    }
92
93
0
    init<Key: UserInfoKey>(_ keyType: Key.Type) {
94
0
      self.keyType = keyType
95
0
    }
96
97
0
    static func == (lhs: AnyUserInfoKey, rhs: AnyUserInfoKey) -> Bool {
98
0
      return ObjectIdentifier(lhs.keyType) == ObjectIdentifier(rhs.keyType)
99
0
    }
100
101
0
    func hash(into hasher: inout Hasher) {
102
0
      hasher.combine(ObjectIdentifier(self.keyType))
103
0
    }
104
  }
105
}
106
107
public protocol UserInfoKey {
108
  /// The type of identified by this key.
109
  associatedtype Value
110
}