Skip to content

Commit

Permalink
require ChannelOptions to be Equatable
Browse files Browse the repository at this point in the history
Motivation:

ChannelOptions should've always been Equatable and so far we've hacked
around them not being Equatable when we wanted to compare them.

Modifications:

make all ChannelOptions Equtable

Result:

- ChannelOption comparison actually works
- fixes apple#598
  • Loading branch information
weissi committed Feb 13, 2019
1 parent 30446ee commit c610c38
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 31 deletions.
23 changes: 2 additions & 21 deletions Sources/NIO/Bootstrap.swift
Original file line number Diff line number Diff line change
Expand Up @@ -675,27 +675,8 @@ public final class DatagramBootstrap {
/* for tests */ internal struct ChannelOptionStorage {
private var storage: [(Any, (Any, (Channel) -> (Any, Any) -> EventLoopFuture<Void>))] = []

mutating func put<K: ChannelOption & Equatable>(key: K, value: K.OptionType) {
return self.put(key: key, value: value, equalsFunc: ==)
}

// HACK: this function should go for NIO 2.0, all ChannelOptions should be equatable
mutating func put<K: ChannelOption>(key: K, value: K.OptionType) {
if K.self == SocketOption.self {
return self.put(key: key as! SocketOption, value: value as! SocketOptionValue) { lhs, rhs in
switch (lhs, rhs) {
case (.const(let lLevel, let lName), .const(let rLevel, let rName)):
return lLevel == rLevel && lName == rName
}
}
} else {
return self.put(key: key, value: value) { _, _ in true }
}
}

mutating func put<K: ChannelOption>(key: K,
value newValue: K.OptionType,
equalsFunc: (K, K) -> Bool) {
value newValue: K.OptionType) {
func applier(_ t: Channel) -> (Any, Any) -> EventLoopFuture<Void> {
return { (x, y) in
return t.setOption(option: x as! K, value: y as! K.OptionType)
Expand All @@ -704,7 +685,7 @@ public final class DatagramBootstrap {
var hasSet = false
self.storage = self.storage.map { typeAndValue in
let (type, value) = typeAndValue
if type is K && equalsFunc(type as! K, key) {
if type is K && type as! K == key {
hasSet = true
return (key, (newValue, applier))
} else {
Expand Down
72 changes: 71 additions & 1 deletion Sources/NIO/ChannelOption.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//

/// A configuration option that can be set on a `Channel` to configure different behaviour.
public protocol ChannelOption {
public protocol ChannelOption: Equatable {
associatedtype AssociatedValueType
associatedtype OptionType

Expand Down Expand Up @@ -70,6 +70,13 @@ public enum SocketOption: ChannelOption {
return (level, name)
}
}

public static func == (lhs: SocketOption, rhs: SocketOption) -> Bool {
switch (lhs, rhs) {
case (.const(let lLevel, let lName), .const(let rLevel, let rName)):
return lLevel == rLevel && lName == rName
}
}
}

/// `AllocatorOption` allows to specify the `ByteBufferAllocator` to use.
Expand All @@ -78,6 +85,13 @@ public enum AllocatorOption: ChannelOption {
public typealias OptionType = ByteBufferAllocator

case const(())

public static func == (lhs: AllocatorOption, rhs: AllocatorOption) -> Bool {
switch (lhs, rhs) {
case (.const(()), .const(())):
return true
}
}
}

/// `RecvAllocatorOption` allows users to specify the `RecvByteBufferAllocator` to use.
Expand All @@ -86,6 +100,13 @@ public enum RecvAllocatorOption: ChannelOption {
public typealias OptionType = RecvByteBufferAllocator

case const(())

public static func == (lhs: RecvAllocatorOption, rhs: RecvAllocatorOption) -> Bool {
switch (lhs, rhs) {
case (.const(()), .const(())):
return true
}
}
}

/// `AutoReadOption` allows users to configure if a `Channel` should automatically call `Channel.read` again once all data was read from the transport or
Expand All @@ -95,6 +116,13 @@ public enum AutoReadOption: ChannelOption {
public typealias OptionType = Bool

case const(())

public static func == (lhs: AutoReadOption, rhs: AutoReadOption) -> Bool {
switch (lhs, rhs) {
case (.const(()), .const(())):
return true
}
}
}

/// `WriteSpinOption` allows users to configure the number of repetitions of a only partially successful write call before considering the `Channel` not writable.
Expand All @@ -105,6 +133,13 @@ public enum WriteSpinOption: ChannelOption {
public typealias OptionType = UInt

case const(())

public static func == (lhs: WriteSpinOption, rhs: WriteSpinOption) -> Bool {
switch (lhs, rhs) {
case (.const(()), .const(())):
return true
}
}
}

/// `MaxMessagesPerReadOption` allows users to configure the maximum number of read calls to the underlying transport are performed before wait again until
Expand All @@ -114,6 +149,13 @@ public enum MaxMessagesPerReadOption: ChannelOption {
public typealias OptionType = UInt

case const(())

public static func == (lhs: MaxMessagesPerReadOption, rhs: MaxMessagesPerReadOption) -> Bool {
switch (lhs, rhs) {
case (.const(()), .const(())):
return true
}
}
}

/// `BacklogOption` allows users to configure the `backlog` value as specified in `man 2 listen`. This is only useful for `ServerSocketChannel`s.
Expand All @@ -122,6 +164,13 @@ public enum BacklogOption: ChannelOption {
public typealias OptionType = Int32

case const(())

public static func == (lhs: BacklogOption, rhs: BacklogOption) -> Bool {
switch (lhs, rhs) {
case (.const(()), .const(())):
return true
}
}
}

/// The watermark used to detect when `Channel.isWritable` returns `true` or `false`.
Expand Down Expand Up @@ -163,6 +212,13 @@ public enum WriteBufferWaterMarkOption: ChannelOption {
public typealias OptionType = WriteBufferWaterMark

case const(())

public static func == (lhs: WriteBufferWaterMarkOption, rhs: WriteBufferWaterMarkOption) -> Bool {
switch (lhs, rhs) {
case (.const(()), .const(())):
return true
}
}
}

/// `ConnectTimeoutOption` allows users to configure the `TimeAmount` after which a connect will fail if it was not established in the meantime. May be
Expand All @@ -172,6 +228,13 @@ public enum ConnectTimeoutOption: ChannelOption {
public typealias OptionType = TimeAmount?

case const(())

public static func == (lhs: ConnectTimeoutOption, rhs: ConnectTimeoutOption) -> Bool {
switch (lhs, rhs) {
case (.const(()), .const(())):
return true
}
}
}

/// `AllowRemoteHalfClosureOption` allows users to configure whether the `Channel` will close itself when its remote
Expand All @@ -184,6 +247,13 @@ public enum AllowRemoteHalfClosureOption: ChannelOption {
public typealias OptionType = Bool

case const(())

public static func == (lhs: AllowRemoteHalfClosureOption, rhs: AllowRemoteHalfClosureOption) -> Bool {
switch (lhs, rhs) {
case (.const(()), .const(())):
return true
}
}
}

/// Provides `ChannelOption`s to be used with a `Channel`, `Bootstrap` or `ServerBootstrap`.
Expand Down
9 changes: 0 additions & 9 deletions Tests/NIOTests/ChannelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2726,12 +2726,3 @@ fileprivate class VerifyConnectionFailureHandler: ChannelInboundHandler {
ctx.fireChannelUnregistered()
}
}

extension SocketOption: Equatable {
public static func == (lhs: SocketOption, rhs: SocketOption) -> Bool {
switch (lhs, rhs) {
case (.const(let lLevel, let lName), .const(let rLevel, let rName)):
return lLevel == rLevel && lName == rName
}
}
}
1 change: 1 addition & 0 deletions docs/public-api-changes-NIO1-to-NIO2.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,4 @@
- renamed `EventLoopFuture.hopTo(eventLoop:)` to `EventLoopFuture.hop(to:)`
- `EventLoopFuture.reduce(into:_:eventLoop:_:)` had its label signature changed to `EventLoopFuture.reduce(into:_:on:_:)`
- `EventLoopFuture.reduce(_:_:eventLoop:_:` had its label signature changed to `EventLoopFuture.reduce(_:_:on:_:)`
- all `ChannelOption`s are now required to be `Equatable`

0 comments on commit c610c38

Please sign in to comment.