Skip to content

Commit

Permalink
Make CommandEvent generic
Browse files Browse the repository at this point in the history
  • Loading branch information
MrLotU committed Sep 28, 2020
1 parent 5e9caa9 commit 07526a7
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 28 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,20 @@ jobs:
swifthooks_macos:
runs-on: macos-latest
env:
DEVELOPER_DIR: /Applications/Xcode_11.4_beta.app/Contents/Developer
DEVELOPER_DIR: /Applications/Xcode_12.app/Contents/Developer
steps:
- uses: actions/checkout@v2
- run: xcrun swift test --enable-test-discovery --sanitize=thread
swifthooks_xenial:
container:
image: vapor/swift:5.2-xenial
image: swift:5.3-xenial
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: swift test --enable-test-discovery --sanitize=thread
swifthooks_bionic:
container:
image: vapor/swift:5.2-bionic
image: swift:5.3-bionic
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
Expand Down
68 changes: 44 additions & 24 deletions Sources/SwiftHooks/Commands/Command.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,26 @@ extension EventLoopFuture: AnyFuture {
}

/// Base command
public struct Command: ExecutableCommand {
public struct Command<EventType>: ExecutableCommand where EventType: _EventType {
public let name: String
public let group: String?
public let alias: [String]
public let hookWhitelist: [HookID]
public let permissionChecks: [CommandPermissionChecker]
public let closure: (CommandEvent) -> AnyFuture
public let closure: (EventType) -> AnyFuture

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

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

public func changeEventType<N>(_ to: N.Type) -> Command<N> {
return .init(name: name, group: group, alias: alias, hookWhitelist: hookWhitelist, permissionChecks: permissionChecks, closure: { e in e.eventLoop.makeSucceededFuture(()) })
}

internal init(name: String, group: String?, alias: [String], hookWhitelist: [HookID], permissionChecks: [CommandPermissionChecker], closure: @escaping Execute) {
self.name = name
self.group = group
Expand All @@ -41,7 +45,7 @@ public struct Command: ExecutableCommand {
///
/// - parameters:
/// - name: Name and trigger of the command.
public init(_ name: String) {
public init(_ name: String) where EventType == CommandEvent {
self.name = name
self.group = nil
self.alias = []
Expand All @@ -60,9 +64,9 @@ public struct Command: ExecutableCommand {
/// - parameters:
/// - t: Type of the argument.
/// - name: Name of the argument.
public func arg<A>(_ t: A.Type, named name: String) -> OneArgCommand<A> {
public func arg<A>(_ t: A.Type, named name: String) -> OneArgCommand<A, EventType> {
let x = GenericCommandArgument<A>(componentType: A.typedName, componentName: name)
return OneArgCommand<A>(
return OneArgCommand<A, EventType>(
name: self.name,
group: group,
alias: alias,
Expand Down Expand Up @@ -93,13 +97,13 @@ fileprivate extension ExecutableCommand {
}

/// Base command with one argument
public struct OneArgCommand<A>: ExecutableCommand where A: CommandArgumentConvertible {
public struct OneArgCommand<A, EventType>: ExecutableCommand where A: CommandArgumentConvertible, EventType: _EventType {
public let name: String
public let group: String?
public let alias: [String]
public let hookWhitelist: [HookID]
public let permissionChecks: [CommandPermissionChecker]
public let closure: (CommandEvent, A.ResolvedArgument) -> AnyFuture
public let closure: (EventType, A.ResolvedArgument) -> AnyFuture
public var readableArguments: String? {
arg.description
}
Expand All @@ -110,6 +114,10 @@ public struct OneArgCommand<A>: ExecutableCommand where A: CommandArgumentConver
return .init(name: name, group: group, alias: alias, hookWhitelist: hookWhitelist, permissionChecks: permissionChecks, closure: closure, arg: arg)
}

public func changeEventType<N>(_ to: N.Type) -> OneArgCommand<A, N> {
return .init(name: name, group: group, alias: alias, hookWhitelist: hookWhitelist, permissionChecks: permissionChecks, closure: { e, _ in e.eventLoop.makeSucceededFuture(()) }, arg: arg)
}

internal init(name: String, group: String?, alias: [String], hookWhitelist: [HookID], permissionChecks: [CommandPermissionChecker], closure: @escaping Execute, arg: CommandArgument) {
self.name = name
self.group = group
Expand All @@ -127,7 +135,7 @@ public struct OneArgCommand<A>: ExecutableCommand where A: CommandArgumentConver
do {
var idx = 0
let a = try getArg(A.self, &idx, for: arg, on: event)
closure(event, a).toVoidFuture().cascade(to: p)
closure(EventType.from(event), a).toVoidFuture().cascade(to: p)
} catch {
p.fail(error)
}
Expand All @@ -142,8 +150,8 @@ public struct OneArgCommand<A>: ExecutableCommand where A: CommandArgumentConver
/// - parameters:
/// - t: Type of the argument.
/// - name: Name of the argument.
public func arg<B>(_ t: B.Type, named name: String) -> TwoArgCommand<A, B> {
return TwoArgCommand<A, B>(
public func arg<B>(_ t: B.Type, named name: String) -> TwoArgCommand<A, B, EventType> {
return TwoArgCommand<A, B, EventType>(
name: self.name,
group: group,
alias: alias,
Expand All @@ -157,13 +165,13 @@ public struct OneArgCommand<A>: ExecutableCommand where A: CommandArgumentConver
}

/// Base command with two arguments
public struct TwoArgCommand<A, B>: ExecutableCommand where A: CommandArgumentConvertible, B: CommandArgumentConvertible {
public struct TwoArgCommand<A, B, EventType>: ExecutableCommand where A: CommandArgumentConvertible, B: CommandArgumentConvertible, EventType: _EventType {
public let name: String
public let group: String?
public let alias: [String]
public let hookWhitelist: [HookID]
public let permissionChecks: [CommandPermissionChecker]
public let closure: (CommandEvent, A.ResolvedArgument, B.ResolvedArgument) -> AnyFuture
public let closure: (EventType, A.ResolvedArgument, B.ResolvedArgument) -> AnyFuture
public var readableArguments: String? {
[argOne, argTwo].map(\.description).joined(separator: " ")
}
Expand All @@ -172,6 +180,10 @@ public struct TwoArgCommand<A, B>: ExecutableCommand where A: CommandArgumentCon
return .init(name: name, group: group, alias: alias, hookWhitelist: hookWhitelist, permissionChecks: permissionChecks, closure: closure, argOne: argOne, argTwo: argTwo)
}

public func changeEventType<N>(_ to: N.Type) -> TwoArgCommand<A, B, N> {
return .init(name: name, group: group, alias: alias, hookWhitelist: hookWhitelist, permissionChecks: permissionChecks, closure: { e, _, _ in e.eventLoop.makeSucceededFuture(()) }, argOne: argOne, argTwo: argTwo)
}

internal init(name: String, group: String?, alias: [String], hookWhitelist: [HookID], permissionChecks: [CommandPermissionChecker], closure: @escaping Execute, argOne: CommandArgument, argTwo: CommandArgument) {
self.name = name
self.group = group
Expand All @@ -198,7 +210,7 @@ public struct TwoArgCommand<A, B>: ExecutableCommand where A: CommandArgumentCon
var idx = 0
let a = try getArg(A.self, &idx, for: argOne, on: event)
let b = try getArg(B.self, &idx, for: argTwo, on: event)
self.closure(event, a, b).toVoidFuture().cascade(to: p)
self.closure(EventType.from(event), a, b).toVoidFuture().cascade(to: p)
} catch {
p.fail(error)
}
Expand All @@ -213,8 +225,8 @@ public struct TwoArgCommand<A, B>: ExecutableCommand where A: CommandArgumentCon
/// - parameters:
/// - t: Type of the argument.
/// - name: Name of the argument.
public func arg<C>(_ t: C.Type, named name: String) -> ThreeArgCommand<A, B, C> {
return ThreeArgCommand<A, B, C>(
public func arg<C>(_ t: C.Type, named name: String) -> ThreeArgCommand<A, B, C, EventType> {
return ThreeArgCommand<A, B, C, EventType>(
name: self.name,
group: group,
alias: alias,
Expand All @@ -229,13 +241,13 @@ public struct TwoArgCommand<A, B>: ExecutableCommand where A: CommandArgumentCon
}

/// Base command with three arguments
public struct ThreeArgCommand<A, B, C>: ExecutableCommand where A: CommandArgumentConvertible, B: CommandArgumentConvertible, C: CommandArgumentConvertible {
public struct ThreeArgCommand<A, B, C, EventType>: ExecutableCommand where A: CommandArgumentConvertible, B: CommandArgumentConvertible, C: CommandArgumentConvertible, EventType: _EventType {
public let name: String
public let group: String?
public let alias: [String]
public let hookWhitelist: [HookID]
public let permissionChecks: [CommandPermissionChecker]
public let closure: (CommandEvent, A.ResolvedArgument, B.ResolvedArgument, C.ResolvedArgument) -> AnyFuture
public let closure: (EventType, A.ResolvedArgument, B.ResolvedArgument, C.ResolvedArgument) -> AnyFuture
public var readableArguments: String? {
[argOne, argTwo, argThree].map(\.description).joined(separator: " ")
}
Expand All @@ -244,6 +256,10 @@ public struct ThreeArgCommand<A, B, C>: ExecutableCommand where A: CommandArgume
return .init(name: name, group: group, alias: alias, hookWhitelist: hookWhitelist, permissionChecks: permissionChecks, closure: closure, argOne: argOne, argTwo: argTwo, argThree: argThree)
}

public func changeEventType<N>(_ to: N.Type) -> ThreeArgCommand<A, B, C, N> {
return .init(name: name, group: group, alias: alias, hookWhitelist: hookWhitelist, permissionChecks: permissionChecks, closure: { e, _, _, _ in e.eventLoop.makeSucceededFuture(()) }, argOne: argOne, argTwo: argTwo, argThree: argThree)
}

internal init(name: String, group: String?, alias: [String], hookWhitelist: [HookID], permissionChecks: [CommandPermissionChecker], closure: @escaping Execute, argOne: CommandArgument, argTwo: CommandArgument, argThree: CommandArgument) {
self.name = name
self.group = group
Expand Down Expand Up @@ -276,7 +292,7 @@ public struct ThreeArgCommand<A, B, C>: ExecutableCommand where A: CommandArgume
let a = try getArg(A.self, &idx, for: argOne, on: event)
let b = try getArg(B.self, &idx, for: argTwo, on: event)
let c = try getArg(C.self, &idx, for: argThree, on: event)
self.closure(event, a, b, c).toVoidFuture().cascade(to: p)
self.closure(EventType.from(event), a, b, c).toVoidFuture().cascade(to: p)
} catch {
p.fail(error)
}
Expand All @@ -291,8 +307,8 @@ public struct ThreeArgCommand<A, B, C>: ExecutableCommand where A: CommandArgume
/// - parameters:
/// - t: Type of the argument.
/// - name: Name of the argument.
public func arg<T>(_ t: T.Type, named name: String) -> ArrayArgCommand where T: CommandArgumentConvertible {
return ArrayArgCommand(
public func arg<T>(_ t: T.Type, named name: String) -> ArrayArgCommand<EventType> where T: CommandArgumentConvertible {
return ArrayArgCommand<EventType>(
name: self.name,
group: group,
alias: alias,
Expand All @@ -305,13 +321,13 @@ public struct ThreeArgCommand<A, B, C>: ExecutableCommand where A: CommandArgume
}

/// Base command with four or more arguments
public struct ArrayArgCommand: ExecutableCommand {
public struct ArrayArgCommand<EventType>: ExecutableCommand where EventType: _EventType {
public let name: String
public let group: String?
public let alias: [String]
public let hookWhitelist: [HookID]
public let permissionChecks: [CommandPermissionChecker]
public let closure: (CommandEvent, Arguments) throws -> AnyFuture
public let closure: (EventType, Arguments) throws -> AnyFuture
/// Arguments for this command.
public let arguments: [CommandArgument]

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

public func changeEventType<N>(_ to: N.Type) -> ArrayArgCommand<N> {
return .init(name: name, group: group, alias: alias, hookWhitelist: hookWhitelist, permissionChecks: permissionChecks, closure: { e, _ in e.eventLoop.makeSucceededFuture(())}, arguments: arguments)
}

internal init(name: String, group: String?, alias: [String], hookWhitelist: [HookID], permissionChecks: [CommandPermissionChecker], closure: @escaping Execute, arguments: [CommandArgument]) {
self.name = name
self.group = group
Expand All @@ -344,7 +364,7 @@ public struct ArrayArgCommand: ExecutableCommand {
public func invoke(on event: CommandEvent) -> EventLoopFuture<Void> {
let p = event.eventLoop.makePromise(of: Void.self)
do {
try closure(event, Arguments(arguments)).toVoidFuture().cascade(to: p)
try closure(EventType.from(event), Arguments(arguments)).toVoidFuture().cascade(to: p)
} catch {
p.fail(error)
}
Expand Down
18 changes: 17 additions & 1 deletion Sources/SwiftHooks/Commands/ExecutableCommand.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import class NIO.EventLoopFuture
import protocol NIO.EventLoop

/// Base `ExecutableCommand`
public protocol _ExecutableCommand: Commands {
Expand Down Expand Up @@ -27,15 +28,30 @@ public protocol _ExecutableCommand: Commands {
func invoke(on event: CommandEvent) -> EventLoopFuture<Void>
}

public protocol _EventType {
static func from(_ event: CommandEvent) -> Self
var eventLoop: EventLoop { get }
}

extension CommandEvent: _EventType {
public static func from(_ event: CommandEvent) -> CommandEvent {
return event
}
}

/// Base `ExecutableCommand`
public protocol ExecutableCommand: _ExecutableCommand {
/// Closure type this command will execute.
associatedtype Execute
/// Closure to execute when command is invoked.
var closure: Execute { get }


associatedtype EventType: _EventType

/// Used for FunctionBuilder Copy On Write.
func copyWith(name: String, group: String?, alias: [String], hookWhitelist: [HookID], permissionChecks: [CommandPermissionChecker], closure: Execute) -> Self

func changeEventType<N>(_ to: N.Type) -> Self where Self.EventType == N
}

public extension ExecutableCommand {
Expand Down

0 comments on commit 07526a7

Please sign in to comment.