Skip to content

Commit 07526a7

Browse files
committed
Make CommandEvent generic
1 parent 5e9caa9 commit 07526a7

3 files changed

Lines changed: 64 additions & 28 deletions

File tree

.github/workflows/test.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,20 @@ jobs:
77
swifthooks_macos:
88
runs-on: macos-latest
99
env:
10-
DEVELOPER_DIR: /Applications/Xcode_11.4_beta.app/Contents/Developer
10+
DEVELOPER_DIR: /Applications/Xcode_12.app/Contents/Developer
1111
steps:
1212
- uses: actions/checkout@v2
1313
- run: xcrun swift test --enable-test-discovery --sanitize=thread
1414
swifthooks_xenial:
1515
container:
16-
image: vapor/swift:5.2-xenial
16+
image: swift:5.3-xenial
1717
runs-on: ubuntu-latest
1818
steps:
1919
- uses: actions/checkout@v2
2020
- run: swift test --enable-test-discovery --sanitize=thread
2121
swifthooks_bionic:
2222
container:
23-
image: vapor/swift:5.2-bionic
23+
image: swift:5.3-bionic
2424
runs-on: ubuntu-latest
2525
steps:
2626
- uses: actions/checkout@v2

Sources/SwiftHooks/Commands/Command.swift

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,26 @@ extension EventLoopFuture: AnyFuture {
1212
}
1313

1414
/// Base command
15-
public struct Command: ExecutableCommand {
15+
public struct Command<EventType>: ExecutableCommand where EventType: _EventType {
1616
public let name: String
1717
public let group: String?
1818
public let alias: [String]
1919
public let hookWhitelist: [HookID]
2020
public let permissionChecks: [CommandPermissionChecker]
21-
public let closure: (CommandEvent) -> AnyFuture
21+
public let closure: (EventType) -> AnyFuture
2222

2323
public func invoke(on event: CommandEvent) -> EventLoopFuture<Void> {
24-
return closure(event).toVoidFuture()
24+
return closure(EventType.from(event)).toVoidFuture()
2525
}
2626

2727
public func copyWith(name: String, group: String?, alias: [String], hookWhitelist: [HookID], permissionChecks: [CommandPermissionChecker], closure: @escaping Execute) -> Self {
2828
return .init(name: name, group: group, alias: alias, hookWhitelist: hookWhitelist, permissionChecks: permissionChecks, closure: closure)
2929
}
3030

31+
public func changeEventType<N>(_ to: N.Type) -> Command<N> {
32+
return .init(name: name, group: group, alias: alias, hookWhitelist: hookWhitelist, permissionChecks: permissionChecks, closure: { e in e.eventLoop.makeSucceededFuture(()) })
33+
}
34+
3135
internal init(name: String, group: String?, alias: [String], hookWhitelist: [HookID], permissionChecks: [CommandPermissionChecker], closure: @escaping Execute) {
3236
self.name = name
3337
self.group = group
@@ -41,7 +45,7 @@ public struct Command: ExecutableCommand {
4145
///
4246
/// - parameters:
4347
/// - name: Name and trigger of the command.
44-
public init(_ name: String) {
48+
public init(_ name: String) where EventType == CommandEvent {
4549
self.name = name
4650
self.group = nil
4751
self.alias = []
@@ -60,9 +64,9 @@ public struct Command: ExecutableCommand {
6064
/// - parameters:
6165
/// - t: Type of the argument.
6266
/// - name: Name of the argument.
63-
public func arg<A>(_ t: A.Type, named name: String) -> OneArgCommand<A> {
67+
public func arg<A>(_ t: A.Type, named name: String) -> OneArgCommand<A, EventType> {
6468
let x = GenericCommandArgument<A>(componentType: A.typedName, componentName: name)
65-
return OneArgCommand<A>(
69+
return OneArgCommand<A, EventType>(
6670
name: self.name,
6771
group: group,
6872
alias: alias,
@@ -93,13 +97,13 @@ fileprivate extension ExecutableCommand {
9397
}
9498

9599
/// Base command with one argument
96-
public struct OneArgCommand<A>: ExecutableCommand where A: CommandArgumentConvertible {
100+
public struct OneArgCommand<A, EventType>: ExecutableCommand where A: CommandArgumentConvertible, EventType: _EventType {
97101
public let name: String
98102
public let group: String?
99103
public let alias: [String]
100104
public let hookWhitelist: [HookID]
101105
public let permissionChecks: [CommandPermissionChecker]
102-
public let closure: (CommandEvent, A.ResolvedArgument) -> AnyFuture
106+
public let closure: (EventType, A.ResolvedArgument) -> AnyFuture
103107
public var readableArguments: String? {
104108
arg.description
105109
}
@@ -110,6 +114,10 @@ public struct OneArgCommand<A>: ExecutableCommand where A: CommandArgumentConver
110114
return .init(name: name, group: group, alias: alias, hookWhitelist: hookWhitelist, permissionChecks: permissionChecks, closure: closure, arg: arg)
111115
}
112116

117+
public func changeEventType<N>(_ to: N.Type) -> OneArgCommand<A, N> {
118+
return .init(name: name, group: group, alias: alias, hookWhitelist: hookWhitelist, permissionChecks: permissionChecks, closure: { e, _ in e.eventLoop.makeSucceededFuture(()) }, arg: arg)
119+
}
120+
113121
internal init(name: String, group: String?, alias: [String], hookWhitelist: [HookID], permissionChecks: [CommandPermissionChecker], closure: @escaping Execute, arg: CommandArgument) {
114122
self.name = name
115123
self.group = group
@@ -127,7 +135,7 @@ public struct OneArgCommand<A>: ExecutableCommand where A: CommandArgumentConver
127135
do {
128136
var idx = 0
129137
let a = try getArg(A.self, &idx, for: arg, on: event)
130-
closure(event, a).toVoidFuture().cascade(to: p)
138+
closure(EventType.from(event), a).toVoidFuture().cascade(to: p)
131139
} catch {
132140
p.fail(error)
133141
}
@@ -142,8 +150,8 @@ public struct OneArgCommand<A>: ExecutableCommand where A: CommandArgumentConver
142150
/// - parameters:
143151
/// - t: Type of the argument.
144152
/// - name: Name of the argument.
145-
public func arg<B>(_ t: B.Type, named name: String) -> TwoArgCommand<A, B> {
146-
return TwoArgCommand<A, B>(
153+
public func arg<B>(_ t: B.Type, named name: String) -> TwoArgCommand<A, B, EventType> {
154+
return TwoArgCommand<A, B, EventType>(
147155
name: self.name,
148156
group: group,
149157
alias: alias,
@@ -157,13 +165,13 @@ public struct OneArgCommand<A>: ExecutableCommand where A: CommandArgumentConver
157165
}
158166

159167
/// Base command with two arguments
160-
public struct TwoArgCommand<A, B>: ExecutableCommand where A: CommandArgumentConvertible, B: CommandArgumentConvertible {
168+
public struct TwoArgCommand<A, B, EventType>: ExecutableCommand where A: CommandArgumentConvertible, B: CommandArgumentConvertible, EventType: _EventType {
161169
public let name: String
162170
public let group: String?
163171
public let alias: [String]
164172
public let hookWhitelist: [HookID]
165173
public let permissionChecks: [CommandPermissionChecker]
166-
public let closure: (CommandEvent, A.ResolvedArgument, B.ResolvedArgument) -> AnyFuture
174+
public let closure: (EventType, A.ResolvedArgument, B.ResolvedArgument) -> AnyFuture
167175
public var readableArguments: String? {
168176
[argOne, argTwo].map(\.description).joined(separator: " ")
169177
}
@@ -172,6 +180,10 @@ public struct TwoArgCommand<A, B>: ExecutableCommand where A: CommandArgumentCon
172180
return .init(name: name, group: group, alias: alias, hookWhitelist: hookWhitelist, permissionChecks: permissionChecks, closure: closure, argOne: argOne, argTwo: argTwo)
173181
}
174182

183+
public func changeEventType<N>(_ to: N.Type) -> TwoArgCommand<A, B, N> {
184+
return .init(name: name, group: group, alias: alias, hookWhitelist: hookWhitelist, permissionChecks: permissionChecks, closure: { e, _, _ in e.eventLoop.makeSucceededFuture(()) }, argOne: argOne, argTwo: argTwo)
185+
}
186+
175187
internal init(name: String, group: String?, alias: [String], hookWhitelist: [HookID], permissionChecks: [CommandPermissionChecker], closure: @escaping Execute, argOne: CommandArgument, argTwo: CommandArgument) {
176188
self.name = name
177189
self.group = group
@@ -198,7 +210,7 @@ public struct TwoArgCommand<A, B>: ExecutableCommand where A: CommandArgumentCon
198210
var idx = 0
199211
let a = try getArg(A.self, &idx, for: argOne, on: event)
200212
let b = try getArg(B.self, &idx, for: argTwo, on: event)
201-
self.closure(event, a, b).toVoidFuture().cascade(to: p)
213+
self.closure(EventType.from(event), a, b).toVoidFuture().cascade(to: p)
202214
} catch {
203215
p.fail(error)
204216
}
@@ -213,8 +225,8 @@ public struct TwoArgCommand<A, B>: ExecutableCommand where A: CommandArgumentCon
213225
/// - parameters:
214226
/// - t: Type of the argument.
215227
/// - name: Name of the argument.
216-
public func arg<C>(_ t: C.Type, named name: String) -> ThreeArgCommand<A, B, C> {
217-
return ThreeArgCommand<A, B, C>(
228+
public func arg<C>(_ t: C.Type, named name: String) -> ThreeArgCommand<A, B, C, EventType> {
229+
return ThreeArgCommand<A, B, C, EventType>(
218230
name: self.name,
219231
group: group,
220232
alias: alias,
@@ -229,13 +241,13 @@ public struct TwoArgCommand<A, B>: ExecutableCommand where A: CommandArgumentCon
229241
}
230242

231243
/// Base command with three arguments
232-
public struct ThreeArgCommand<A, B, C>: ExecutableCommand where A: CommandArgumentConvertible, B: CommandArgumentConvertible, C: CommandArgumentConvertible {
244+
public struct ThreeArgCommand<A, B, C, EventType>: ExecutableCommand where A: CommandArgumentConvertible, B: CommandArgumentConvertible, C: CommandArgumentConvertible, EventType: _EventType {
233245
public let name: String
234246
public let group: String?
235247
public let alias: [String]
236248
public let hookWhitelist: [HookID]
237249
public let permissionChecks: [CommandPermissionChecker]
238-
public let closure: (CommandEvent, A.ResolvedArgument, B.ResolvedArgument, C.ResolvedArgument) -> AnyFuture
250+
public let closure: (EventType, A.ResolvedArgument, B.ResolvedArgument, C.ResolvedArgument) -> AnyFuture
239251
public var readableArguments: String? {
240252
[argOne, argTwo, argThree].map(\.description).joined(separator: " ")
241253
}
@@ -244,6 +256,10 @@ public struct ThreeArgCommand<A, B, C>: ExecutableCommand where A: CommandArgume
244256
return .init(name: name, group: group, alias: alias, hookWhitelist: hookWhitelist, permissionChecks: permissionChecks, closure: closure, argOne: argOne, argTwo: argTwo, argThree: argThree)
245257
}
246258

259+
public func changeEventType<N>(_ to: N.Type) -> ThreeArgCommand<A, B, C, N> {
260+
return .init(name: name, group: group, alias: alias, hookWhitelist: hookWhitelist, permissionChecks: permissionChecks, closure: { e, _, _, _ in e.eventLoop.makeSucceededFuture(()) }, argOne: argOne, argTwo: argTwo, argThree: argThree)
261+
}
262+
247263
internal init(name: String, group: String?, alias: [String], hookWhitelist: [HookID], permissionChecks: [CommandPermissionChecker], closure: @escaping Execute, argOne: CommandArgument, argTwo: CommandArgument, argThree: CommandArgument) {
248264
self.name = name
249265
self.group = group
@@ -276,7 +292,7 @@ public struct ThreeArgCommand<A, B, C>: ExecutableCommand where A: CommandArgume
276292
let a = try getArg(A.self, &idx, for: argOne, on: event)
277293
let b = try getArg(B.self, &idx, for: argTwo, on: event)
278294
let c = try getArg(C.self, &idx, for: argThree, on: event)
279-
self.closure(event, a, b, c).toVoidFuture().cascade(to: p)
295+
self.closure(EventType.from(event), a, b, c).toVoidFuture().cascade(to: p)
280296
} catch {
281297
p.fail(error)
282298
}
@@ -291,8 +307,8 @@ public struct ThreeArgCommand<A, B, C>: ExecutableCommand where A: CommandArgume
291307
/// - parameters:
292308
/// - t: Type of the argument.
293309
/// - name: Name of the argument.
294-
public func arg<T>(_ t: T.Type, named name: String) -> ArrayArgCommand where T: CommandArgumentConvertible {
295-
return ArrayArgCommand(
310+
public func arg<T>(_ t: T.Type, named name: String) -> ArrayArgCommand<EventType> where T: CommandArgumentConvertible {
311+
return ArrayArgCommand<EventType>(
296312
name: self.name,
297313
group: group,
298314
alias: alias,
@@ -305,13 +321,13 @@ public struct ThreeArgCommand<A, B, C>: ExecutableCommand where A: CommandArgume
305321
}
306322

307323
/// Base command with four or more arguments
308-
public struct ArrayArgCommand: ExecutableCommand {
324+
public struct ArrayArgCommand<EventType>: ExecutableCommand where EventType: _EventType {
309325
public let name: String
310326
public let group: String?
311327
public let alias: [String]
312328
public let hookWhitelist: [HookID]
313329
public let permissionChecks: [CommandPermissionChecker]
314-
public let closure: (CommandEvent, Arguments) throws -> AnyFuture
330+
public let closure: (EventType, Arguments) throws -> AnyFuture
315331
/// Arguments for this command.
316332
public let arguments: [CommandArgument]
317333

@@ -323,6 +339,10 @@ public struct ArrayArgCommand: ExecutableCommand {
323339
return .init(name: name, group: group, alias: alias, hookWhitelist: hookWhitelist, permissionChecks: permissionChecks, closure: closure, arguments: arguments)
324340
}
325341

342+
public func changeEventType<N>(_ to: N.Type) -> ArrayArgCommand<N> {
343+
return .init(name: name, group: group, alias: alias, hookWhitelist: hookWhitelist, permissionChecks: permissionChecks, closure: { e, _ in e.eventLoop.makeSucceededFuture(())}, arguments: arguments)
344+
}
345+
326346
internal init(name: String, group: String?, alias: [String], hookWhitelist: [HookID], permissionChecks: [CommandPermissionChecker], closure: @escaping Execute, arguments: [CommandArgument]) {
327347
self.name = name
328348
self.group = group
@@ -344,7 +364,7 @@ public struct ArrayArgCommand: ExecutableCommand {
344364
public func invoke(on event: CommandEvent) -> EventLoopFuture<Void> {
345365
let p = event.eventLoop.makePromise(of: Void.self)
346366
do {
347-
try closure(event, Arguments(arguments)).toVoidFuture().cascade(to: p)
367+
try closure(EventType.from(event), Arguments(arguments)).toVoidFuture().cascade(to: p)
348368
} catch {
349369
p.fail(error)
350370
}

Sources/SwiftHooks/Commands/ExecutableCommand.swift

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import class NIO.EventLoopFuture
2+
import protocol NIO.EventLoop
23

34
/// Base `ExecutableCommand`
45
public protocol _ExecutableCommand: Commands {
@@ -27,15 +28,30 @@ public protocol _ExecutableCommand: Commands {
2728
func invoke(on event: CommandEvent) -> EventLoopFuture<Void>
2829
}
2930

31+
public protocol _EventType {
32+
static func from(_ event: CommandEvent) -> Self
33+
var eventLoop: EventLoop { get }
34+
}
35+
36+
extension CommandEvent: _EventType {
37+
public static func from(_ event: CommandEvent) -> CommandEvent {
38+
return event
39+
}
40+
}
41+
3042
/// Base `ExecutableCommand`
3143
public protocol ExecutableCommand: _ExecutableCommand {
3244
/// Closure type this command will execute.
3345
associatedtype Execute
3446
/// Closure to execute when command is invoked.
3547
var closure: Execute { get }
36-
48+
49+
associatedtype EventType: _EventType
50+
3751
/// Used for FunctionBuilder Copy On Write.
3852
func copyWith(name: String, group: String?, alias: [String], hookWhitelist: [HookID], permissionChecks: [CommandPermissionChecker], closure: Execute) -> Self
53+
54+
func changeEventType<N>(_ to: N.Type) -> Self where Self.EventType == N
3955
}
4056

4157
public extension ExecutableCommand {

0 commit comments

Comments
 (0)