Skip to content

Commit

Permalink
Merge pull request #22 from orchetect/dev
Browse files Browse the repository at this point in the history
Added `AnyUniqueID` and `AnyEndpoint`
  • Loading branch information
orchetect authored Aug 3, 2021
2 parents 249848e + 950cfe1 commit 24ad8bc
Show file tree
Hide file tree
Showing 16 changed files with 307 additions and 8 deletions.
49 changes: 49 additions & 0 deletions Sources/MIDIKit/IO/Objects/Endpoint/AnyEndpoint/AnyEndpoint.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// AnyEndpoint.swift
// MIDIKit • https://github.com/orchetect/MIDIKit
//

import CoreMIDI

extension MIDI.IO {

/// Type-erased box that can contain `MIDI.IO.InputEndpoint` or `MIDI.IO.OutputEndpoint`.
public struct AnyEndpoint: MIDIIOEndpointProtocol {

public let endpointType: MIDI.IO.EndpointType

public let coreMIDIObjectRef: MIDIEndpointRef

public let name: String

public var uniqueID: UniqueID

internal init<T: MIDIIOEndpointProtocol>(_ other: T) {
switch other {
case is MIDI.IO.InputEndpoint:
endpointType = .input

case is MIDI.IO.OutputEndpoint:
endpointType = .output

case let otherCast as Self:
endpointType = otherCast.endpointType

default:
preconditionFailure("Unexpected MIDIIOEndpointProtocol type: \(other)")
}

self.coreMIDIObjectRef = other.coreMIDIObjectRef
self.name = other.name
self.uniqueID = .init(other.uniqueID.coreMIDIUniqueID)
}

}

}

extension MIDI.IO.AnyEndpoint {

public typealias UniqueID = MIDI.IO.AnyUniqueID

}
13 changes: 13 additions & 0 deletions Sources/MIDIKit/IO/Objects/Endpoint/EndpointType.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// EndpointType.swift
// MIDIKit • https://github.com/orchetect/MIDIKit
//

extension MIDI.IO {

public enum EndpointType: Equatable, Hashable, CaseIterable {
case input
case output
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,8 @@ extension MIDI.IO {

// MARK: - Properties (Cached)

/// User-visible endpoint name.
/// (`kMIDIPropertyName`)
public internal(set) var name: String = ""

/// System-global Unique ID.
/// (`kMIDIPropertyUniqueID`)
public internal(set) var uniqueID: UniqueID = 0

/// Update the cached properties
Expand Down Expand Up @@ -76,6 +72,14 @@ extension MIDI.IO.InputEndpoint {

}

extension MIDI.IO.InputEndpoint {

/// Returns the endpoint as a type-erased `AnyEndpoint`.
public var asAnyEndpoint: MIDI.IO.AnyEndpoint {
.init(self)
}

}

extension MIDI.IO.InputEndpoint: CustomDebugStringConvertible {

Expand Down
11 changes: 11 additions & 0 deletions Sources/MIDIKit/IO/Objects/Endpoint/MIDIIOEndpointProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,14 @@ extension MIDIIOEndpointProtocol {
}

}

extension Collection where Element : MIDIIOEndpointProtocol {

/// Returns the collection as a collection of type-erased `AnyEndpoint` endpoints.
public var asAnyEndpoints: [MIDI.IO.AnyEndpoint] {

map { MIDI.IO.AnyEndpoint($0) }

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,8 @@ extension MIDI.IO {

// MARK: - Properties (Cached)

/// User-visible endpoint name.
/// (`kMIDIPropertyName`)
public internal(set) var name: String = ""

/// System-global Unique ID.
/// (`kMIDIPropertyUniqueID`)
public internal(set) var uniqueID: UniqueID = 0

/// Update the cached properties
Expand Down Expand Up @@ -76,6 +72,15 @@ extension MIDI.IO.OutputEndpoint {

}

extension MIDI.IO.OutputEndpoint {

/// Returns the endpoint as a type-erased `AnyEndpoint`.
public var asAnyEndpoint: MIDI.IO.AnyEndpoint {
.init(self)
}

}

extension MIDI.IO.OutputEndpoint: CustomDebugStringConvertible {

public var debugDescription: String {
Expand Down
70 changes: 70 additions & 0 deletions Sources/MIDIKit/IO/UniqueID/AnyUniqueID.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//
// AnyUniqueID.swift
// MIDIKit • https://github.com/orchetect/MIDIKit
//

import CoreMIDI

extension MIDI.IO {

/// Type-erased box for `MIDIIOUniqueIDProtocol`.
///
/// MIDIKit Object Unique ID value type.
/// Analogous with CoreMIDI value of `MIDIObjectRef` property key `kMIDIPropertyUniqueID`.
public struct AnyUniqueID: MIDIIOUniqueIDProtocol {

public let coreMIDIUniqueID: MIDIUniqueID

public init(_ coreMIDIUniqueID: MIDIUniqueID) {
self.coreMIDIUniqueID = coreMIDIUniqueID
}

}

}

extension MIDI.IO.AnyEndpoint.UniqueID: Equatable {
// default implementation provided by MIDIIOUniqueIDProtocol
}

extension MIDI.IO.AnyEndpoint.UniqueID: Hashable {
// default implementation provided by MIDIIOUniqueIDProtocol
}

extension MIDI.IO.AnyEndpoint.UniqueID: Identifiable {
// default implementation provided by MIDIIOUniqueIDProtocol
}

extension MIDI.IO.AnyEndpoint.UniqueID: ExpressibleByIntegerLiteral {

public typealias IntegerLiteralType = MIDIUniqueID

public init(integerLiteral value: IntegerLiteralType) {

coreMIDIUniqueID = value

}

}

extension MIDI.IO.AnyEndpoint.UniqueID: CustomStringConvertible {

public var description: String {

return "\(coreMIDIUniqueID)"

}

}

extension MIDIIOUniqueIDProtocol {

/// Returns the unique ID as a type-erased `AnyUniqueID`.
public var asAnyUniqueID: MIDI.IO.AnyUniqueID {

.init(coreMIDIUniqueID)

}

}

11 changes: 11 additions & 0 deletions Sources/MIDIKit/IO/UniqueID/MIDIIOUniqueIDProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,17 @@ public protocol MIDIIOUniqueIDProtocol {

}

extension Collection where Element == MIDIIOUniqueIDProtocol {

/// Returns the collection as a collection of type-erased `AnyUniqueID` unique IDs.
public var asAnyUniqueIDs: [MIDI.IO.AnyUniqueID] {

map { MIDI.IO.AnyUniqueID($0.coreMIDIUniqueID) }

}

}

// MARK: - MIDIIOEndpointUniqueIDProtocol

public protocol MIDIIOEndpointUniqueIDProtocol: MIDIIOUniqueIDProtocol {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ final class Manager_Tests: XCTestCase {

func testMIDIO_Manager_defaults() {

// just check defaults without calling .start() on the manager

XCTAssertEqual(manager.clientName, "MIDIKit_IO_Manager_Tests")
XCTAssertEqual(manager.clientRef, MIDIClientRef())

Expand Down
101 changes: 101 additions & 0 deletions Tests/MIDIKitTests/IO/Objects/Endpoint/AnyEndpoint Tests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
//
// AnyEndpoint Tests.swift
// MIDIKit • https://github.com/orchetect/MIDIKit
//

// iOS Simulator XCTest testing does not give enough permissions to allow creating virtual MIDI ports, so skip these tests on iOS targets
#if !os(watchOS) && !targetEnvironment(simulator)

import XCTest
@testable import MIDIKit

class AnyEndpoint_Tests: XCTestCase {

var manager: MIDI.IO.Manager! = nil

override func setUp() {
manager = .init(clientName: "MIDIKit_IO_AnyEndpoint_Tests",
model: "",
manufacturer: "")

guard let _ = try? manager.start() else {
XCTFail("Couldn't start MIDI.IO.Manager.")
return
}
}

override func tearDown() {
manager = nil
}

func testAnyEndpoint() throws {

// to properly test this, we need to actually
// create a couple MIDI endpoints in the system first

let kInputName = "MIDIKit Test Input"
let kInputTag = "testInput"
try manager.addInput(name: kInputName,
tag: kInputTag,
uniqueID: .none,
receiveHandler: .rawDataLogging())

let kOutputName = "MIDIKit Test Output"
let kOutputTag = "testOutput"
try manager.addOutput(name: kOutputName,
tag: kOutputTag,
uniqueID: .none)

// have to give CoreMIDI a bit of time to create the ports (async)
XCTWait(sec: 1.0)

// input

guard let inputUniqueID = manager.managedInputs[kInputTag]?.uniqueID,
let inputEndpoint = manager.endpoints.inputs.first(whereUniqueID: inputUniqueID)
else { XCTFail() ; return }

let anyInput = MIDI.IO.AnyEndpoint(inputEndpoint)
_ = inputEndpoint.asAnyEndpoint // also works
XCTAssertEqual(anyInput.coreMIDIObjectRef, inputEndpoint.coreMIDIObjectRef)
XCTAssertEqual(anyInput.name, kInputName)
XCTAssertEqual(anyInput.endpointType, .input)

// output

guard let outputUniqueID = manager.managedOutputs[kOutputTag]?.uniqueID,
let outputEndpoint = manager.endpoints.outputs.first(whereUniqueID: outputUniqueID)
else { XCTFail() ; return }

let anyOutput = MIDI.IO.AnyEndpoint(outputEndpoint)
_ = outputEndpoint.asAnyEndpoint // also works
XCTAssertEqual(outputEndpoint.coreMIDIObjectRef, anyOutput.coreMIDIObjectRef)
XCTAssertEqual(anyOutput.name, kOutputName)
XCTAssertEqual(anyOutput.endpointType, .output)

// Collection

let inputArray = [inputEndpoint]
let inputArrayAsAnyEndpoints = inputArray.asAnyEndpoints
XCTAssertEqual(inputArrayAsAnyEndpoints.count, 1)
XCTAssertEqual(inputArrayAsAnyEndpoints[0].coreMIDIObjectRef, inputEndpoint.coreMIDIObjectRef)

let outputArray = [outputEndpoint]
let outputArrayAsAnyEndpoints = outputArray.asAnyEndpoints
XCTAssertEqual(outputArrayAsAnyEndpoints.count, 1)
XCTAssertEqual(outputArrayAsAnyEndpoints[0].coreMIDIObjectRef, outputEndpoint.coreMIDIObjectRef)

let combined = inputArrayAsAnyEndpoints + outputArrayAsAnyEndpoints
XCTAssertEqual(combined.count, 2)

// AnyEndpoint from AnyEndpoint (just to check for crashes)
let anyAny = MIDI.IO.AnyEndpoint(anyInput)
XCTAssertEqual(anyAny.coreMIDIObjectRef, anyInput.coreMIDIObjectRef)
XCTAssertEqual(anyAny.name, anyInput.name)
XCTAssertEqual(anyAny.endpointType, .input)
XCTAssertEqual(anyAny.uniqueID, anyInput.uniqueID)

}

}
#endif
33 changes: 33 additions & 0 deletions Tests/MIDIKitTests/IO/UniqueID/AnyUniqueID Tests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// AnyUniqueID Tests.swift
// MIDIKit • https://github.com/orchetect/MIDIKit
//

#if !os(watchOS)

import XCTest
@testable import MIDIKit

class AnyUniqueID_Tests: XCTestCase {

func testAnyUniqueID() {

let allUniqueIDTypes: [MIDIIOUniqueIDProtocol] = [
MIDI.IO.Device.UniqueID(10000000),
MIDI.IO.Entity.UniqueID(10000001),
MIDI.IO.InputEndpoint.UniqueID(10000002),
MIDI.IO.OutputEndpoint.UniqueID(10000003)
]

let anyArray = allUniqueIDTypes.asAnyUniqueIDs

XCTAssertEqual(anyArray.count, 4)
XCTAssertEqual(anyArray[0].coreMIDIUniqueID, 10000000)
XCTAssertEqual(anyArray[1].coreMIDIUniqueID, 10000001)
XCTAssertEqual(anyArray[2].coreMIDIUniqueID, 10000002)
XCTAssertEqual(anyArray[3].coreMIDIUniqueID, 10000003)

}

}
#endif

0 comments on commit 24ad8bc

Please sign in to comment.