File: ConvenienceOptionSupport.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 (186 lines) | stat: -rw-r--r-- 7,710 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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftNIO open source project
//
// Copyright (c) 2020 Apple Inc. and the SwiftNIO project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

// MARK:  Universal Client Bootstrap
extension NIOClientTCPBootstrapProtocol {
    /// Apply any understood convenience options to the bootstrap, removing them from the set of options if they are consumed.
    /// - parameters:
    ///     - options:  The options to try applying - the options applied should be consumed from here.
    /// - returns: The updated bootstrap with and options applied.
    public func _applyChannelConvenienceOptions(_ options: inout ChannelOptions.TCPConvenienceOptions) -> Self {
        // Default is to consume no options and not update self.
        return self
    }
}

extension NIOClientTCPBootstrap {
    /// Specifies some `TCPConvenienceOption`s to be applied to the channel.
    /// These are preferred over regular channel options as they are easier to use and restrict
    /// options to those which a normal user would consider.
    /// - Parameter options: Set of convenience options to apply.
    /// - Returns: The updated bootstrap (`self` being mutated)
    public func channelConvenienceOptions(_ options: ChannelOptions.TCPConvenienceOptions) -> NIOClientTCPBootstrap {
        var optionsRemaining = options
        // First give the underlying a chance to consume options.
        let withUnderlyingOverrides =
            NIOClientTCPBootstrap(self,
                                  updating: underlyingBootstrap._applyChannelConvenienceOptions(&optionsRemaining))
        // Default apply any remaining options.
        return optionsRemaining.applyFallbackMapping(withUnderlyingOverrides)
    }
}

// MARK: Utility
extension ChannelOptions.Types {
    /// Has an option been set?
    /// Option has a value of generic type ValueType.
    public enum ConvenienceOptionValue<ValueType> {
        /// The option was not set.
        case notSet
        /// The option was set with a value of type ValueType.
        case set(ValueType)
    }
}

extension ChannelOptions.Types.ConvenienceOptionValue where ValueType == () {
    /// Convenience method working with bool options as bool values for set.
    public var isSet: Bool {
        get {
            switch self {
            case .notSet:
                return false
            case .set(()):
                return true
            }
        }
    }
}

extension ChannelOptions.Types.ConvenienceOptionValue where ValueType == () {
    fileprivate init(flag: Bool) {
        if flag {
            self = .set(())
        } else {
            self = .notSet
        }
    }
}

// MARK: TCP - data
extension ChannelOptions {
    /// A TCP channel option which can be applied to a bootstrap using convenience notation.
    public struct TCPConvenienceOption: Hashable {
        fileprivate var data: ConvenienceOption
        
        private init(_ data: ConvenienceOption) {
            self.data = data
        }
        
        fileprivate enum ConvenienceOption: Hashable {
            case allowLocalEndpointReuse
            case disableAutoRead
            case allowRemoteHalfClosure
        }
    }
}

/// Approved convenience options.
extension ChannelOptions.TCPConvenienceOption {
    /// Allow immediately reusing a local address.
    public static let allowLocalEndpointReuse = ChannelOptions.TCPConvenienceOption(.allowLocalEndpointReuse)
    
    /// The user will manually call `Channel.read` once all the data is read from the transport.
    public static let disableAutoRead = ChannelOptions.TCPConvenienceOption(.disableAutoRead)
    
    /// Allows users to configure whether the `Channel` will close itself when its remote
    /// peer shuts down its send stream, or whether it will remain open. If set to `false` (the default), the `Channel`
    /// will be closed automatically if the remote peer shuts down its send stream. If set to true, the `Channel` will
    /// not be closed: instead, a `ChannelEvent.inboundClosed` user event will be sent on the `ChannelPipeline`,
    /// and no more data will be received.
    public static let allowRemoteHalfClosure =
                        ChannelOptions.TCPConvenienceOption(.allowRemoteHalfClosure)
}

extension ChannelOptions {
    /// A set of `TCPConvenienceOption`s
    public struct TCPConvenienceOptions: ExpressibleByArrayLiteral, Hashable {
        var allowLocalEndpointReuse = false
        var disableAutoRead = false
        var allowRemoteHalfClosure = false
        
        /// Construct from an array literal.
        @inlinable
        public init(arrayLiteral elements: TCPConvenienceOption...) {
            for element in elements {
                self.add(element)
            }
        }
        
        @usableFromInline
        mutating func add(_ element: TCPConvenienceOption) {
            switch element.data {
            case .allowLocalEndpointReuse:
                self.allowLocalEndpointReuse = true
            case .allowRemoteHalfClosure:
                self.allowRemoteHalfClosure = true
            case .disableAutoRead:
                self.disableAutoRead = true
            }
        }
        
        /// Caller is consuming the knowledge that `allowLocalEndpointReuse` was set or not.
        /// The setting will nolonger be set after this call.
        /// - Returns: If `allowLocalEndpointReuse` was set.
        public mutating func consumeAllowLocalEndpointReuse() -> Types.ConvenienceOptionValue<Void> {
            defer {
                self.allowLocalEndpointReuse = false
            }
            return Types.ConvenienceOptionValue<Void>(flag: self.allowLocalEndpointReuse)
        }
        
        /// Caller is consuming the knowledge that disableAutoRead was set or not.
        /// The setting will nolonger be set after this call.
        /// - Returns: If disableAutoRead was set.
        public mutating func consumeDisableAutoRead() -> Types.ConvenienceOptionValue<Void> {
            defer {
                self.disableAutoRead = false
            }
            return Types.ConvenienceOptionValue<Void>(flag: self.disableAutoRead)
        }
        
        /// Caller is consuming the knowledge that allowRemoteHalfClosure was set or not.
        /// The setting will nolonger be set after this call.
        /// - Returns: If allowRemoteHalfClosure was set.
        public mutating func consumeAllowRemoteHalfClosure() -> Types.ConvenienceOptionValue<Void> {
            defer {
                self.allowRemoteHalfClosure = false
            }
            return Types.ConvenienceOptionValue<Void>(flag: self.allowRemoteHalfClosure)
        }
        
        mutating func applyFallbackMapping(_ universalBootstrap: NIOClientTCPBootstrap) -> NIOClientTCPBootstrap {
            var result = universalBootstrap
            if self.consumeAllowLocalEndpointReuse().isSet {
                result = result.channelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)
            }
            if self.consumeAllowRemoteHalfClosure().isSet {
                result = result.channelOption(ChannelOptions.allowRemoteHalfClosure, value: true)
            }
            if self.consumeDisableAutoRead().isSet {
                result = result.channelOption(ChannelOptions.autoRead, value: false)
            }
            return result
        }
    }
}