/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 | | } |