From 80589ada6987241e29e287046e46d4bdfffab353 Mon Sep 17 00:00:00 2001 From: Steffan Andrews Date: Thu, 1 Sep 2022 16:36:45 -0700 Subject: [PATCH] Moved protocol implementations into concrete custom UInts from private protocol --- .../Types/MIDIUnsignedInteger.swift | 217 +---------------- Sources/MIDIKitCore/Types/UInt14.swift | 219 +++++++++++++++++- Sources/MIDIKitCore/Types/UInt25.swift | 219 +++++++++++++++++- Sources/MIDIKitCore/Types/UInt4.swift | 219 +++++++++++++++++- Sources/MIDIKitCore/Types/UInt7.swift | 219 +++++++++++++++++- Sources/MIDIKitCore/Types/UInt9.swift | 219 +++++++++++++++++- 6 files changed, 1061 insertions(+), 251 deletions(-) diff --git a/Sources/MIDIKitCore/Types/MIDIUnsignedInteger.swift b/Sources/MIDIKitCore/Types/MIDIUnsignedInteger.swift index ef3c52cfdd..620de32801 100644 --- a/Sources/MIDIKitCore/Types/MIDIUnsignedInteger.swift +++ b/Sources/MIDIKitCore/Types/MIDIUnsignedInteger.swift @@ -110,72 +110,6 @@ extension _MIDIUnsignedInteger { } } -// MARK: - Equatable - -// Equatable must be implemented on the type itself to make the compiler happy -// when importing the umbrella MIDIKit library product in a project or package -// even when only importing certain targets. - -// MARK: - Comparable - -extension _MIDIUnsignedInteger /*: Comparable */ { - public static func < (lhs: Self, rhs: Self) -> Bool { - lhs.storage < rhs.storage - } -} - -// MARK: - Hashable - -extension _MIDIUnsignedInteger /*: Hashable */ { - public func hash(into hasher: inout Hasher) { - hasher.combine(storage) - } -} - -// MARK: - Codable - -extension _MIDIUnsignedInteger /*: Codable */ { - public func encode(to encoder: Encoder) throws { - var e = encoder.singleValueContainer() - try e.encode(storage) - } - - public init(from decoder: Decoder) throws { - let d = try decoder.singleValueContainer() - let decoded = try d.decode(Storage.self) - guard let new = Self(exactly: decoded) else { - throw DecodingError.dataCorrupted( - .init(codingPath: decoder.codingPath, - debugDescription: "Encoded value is not a valid \(Self.integerName).") - ) - } - self = new - } -} - -// MARK: - CustomStringConvertible - -extension _MIDIUnsignedInteger {//: CustomStringConvertible, CustomDebugStringConvertible { - public var description: String { - storage.description - } - - public var debugDescription: String { - "\(Self.integerName)(\(storage.description))" - } -} - -// MARK: - ExpressibleByIntegerLiteral - -extension MIDIUnsignedInteger /*: ExpressibleByIntegerLiteral */ { - //public typealias IntegerLiteralType = Storage - // IntegerLiteralType is already expressed as same-type constraint on MIDIUnsignedInteger - - public init(integerLiteral value: Storage) { - self.init(value) - } -} - // MARK: - Strideable extension MIDIUnsignedInteger /*: Strideable */ { @@ -191,152 +125,13 @@ extension MIDIUnsignedInteger /*: Strideable */ { } } -// MARK: - _MIDIUnsignedInteger Default Implementation - -extension _MIDIUnsignedInteger { - static func min(as ofType: T.Type) -> T { 0 } - static func min(as ofType: T.Type) -> T { 0 } - - static func max(as ofType: T.Type) -> T { - (0 ..< bitWidth) - .reduce(into: T()) { $0 |= (0b1 << $1) } - } - - static func max(as ofType: T.Type) -> T { - T(max(as: Int.self)) - } -} - -// MARK: - MIDIUnsignedInteger Conveniences - -extension _MIDIUnsignedInteger { - /// Returns the integer converted to an `Int` instance (convenience). - public var intValue: Int { Int(storage) } -} - -// MARK: - FixedWidthInteger - -extension _MIDIUnsignedInteger /*: FixedWidthInteger */ { - public static var min: Self { Self(Self.min(as: Storage.self)) } - - public static var max: Self { Self(Self.max(as: Storage.self)) } - - // this would be synthesized if MIDIUnsignedInteger conformed to FixedWidthInteger - public static func >>= (lhs: inout Self, rhs: RHS) where RHS : BinaryInteger { - lhs.storage >>= rhs - } - - // this would be synthesized if MIDIUnsignedInteger conformed to FixedWidthInteger - public static func <<= (lhs: inout Self, rhs: RHS) where RHS : BinaryInteger { - lhs.storage <<= rhs - } -} - -// MARK: - Numeric - -extension _MIDIUnsignedInteger /*: Numeric */ { - // public typealias Magnitude = Storage.Magnitude - // Magnitude is already expressed as same-type constraint on MIDIUnsignedInteger - - public var magnitude: Storage.Magnitude { - storage.magnitude - } - - public init?(exactly source: T) where T: BinaryInteger { - if source < Self.min(as: Storage.self) || - source > Self.max(as: Storage.self) - { - return nil - } - self.init(unchecked: Storage(source)) - } - - public static func * (lhs: Self, rhs: Self) -> Self { - Self(lhs.storage * rhs.storage) - } - - public static func *= (lhs: inout Self, rhs: Self) { - lhs = Self(lhs.storage * rhs.storage) - } -} - -// MARK: - AdditiveArithmetic - -extension _MIDIUnsignedInteger /*: AdditiveArithmetic */ { - // static let zero synthesized by AdditiveArithmetic - - public static func + (lhs: Self, rhs: Self) -> Self { - Self(lhs.storage + rhs.storage) - } - - // += operator synthesized by AdditiveArithmetic - - public static func - (lhs: Self, rhs: Self) -> Self { - Self(lhs.storage - rhs.storage) - } - - // -= operator synthesized by AdditiveArithmetic -} - -// MARK: - BinaryInteger +// MARK: - ExpressibleByIntegerLiteral -extension _MIDIUnsignedInteger /*: BinaryInteger */ { - // public typealias Words = Storage.Words - // Words is already expressed as same-type constraint on MIDIUnsignedInteger - - public var words: Storage.Words { - storage.words - } - - // synthesized? - // public static var isSigned: Bool { false } - - public var bitWidth: Int { Self.bitWidth } - - public var trailingZeroBitCount: Int { - storage.trailingZeroBitCount - (storage.bitWidth - Self.bitWidth) - } - - public static func / (lhs: Self, rhs: Self) -> Self { - Self(lhs.storage / rhs.storage) - } - - public static func /= (lhs: inout Self, rhs: Self) { - lhs = Self(lhs.storage / rhs.storage) - } - - public static func % (lhs: Self, rhs: Self) -> Self { - Self(lhs.storage % rhs.storage) - } - - public static func << (lhs: Self, rhs: RHS) -> Self - where RHS: BinaryInteger { - Self(lhs.storage << rhs) - } - - public static func >> (lhs: Self, rhs: RHS) -> Self - where RHS: BinaryInteger { - Self(lhs.storage >> rhs) - } - - public static func %= (lhs: inout Self, rhs: Self) { - lhs.storage %= rhs.storage - } - - public static func &= (lhs: inout Self, rhs: Self) { - lhs.storage &= rhs.storage - } - - public static func |= (lhs: inout Self, rhs: Self) { - lhs.storage |= rhs.storage - } - - public static func ^= (lhs: inout Self, rhs: Self) { - lhs.storage ^= rhs.storage - } +extension MIDIUnsignedInteger /*: ExpressibleByIntegerLiteral */ { + //public typealias IntegerLiteralType = Storage + // IntegerLiteralType is already expressed as same-type constraint on MIDIUnsignedInteger - public static prefix func ~ (x: Self) -> Self { - // mask to bit width - Self(unchecked: ~x.storage & Self.max(as: Self.self).storage) + public init(integerLiteral value: Storage) { + self.init(value) } } diff --git a/Sources/MIDIKitCore/Types/UInt14.swift b/Sources/MIDIKitCore/Types/UInt14.swift index 6f5782f348..846c580cc7 100644 --- a/Sources/MIDIKitCore/Types/UInt14.swift +++ b/Sources/MIDIKitCore/Types/UInt14.swift @@ -34,14 +34,6 @@ extension UInt14 { public static let bitWidth: Int = 14 } -// MARK: - Equatable - -extension UInt14 /*: Equatable */ { - public static func == (lhs: Self, rhs: Self) -> Bool { - lhs.storage == rhs.storage - } -} - // MARK: - Standard library extensions extension BinaryInteger { @@ -144,3 +136,214 @@ extension UInt14 { return .init(msb: UInt7(msb), lsb: UInt7(lsb)) } } + +// ---------------------------------------- +// MARK: - Common Conformances Across UInts +// ---------------------------------------- + +// MARK: - Equatable + +extension UInt14 /*: Equatable */ { + public static func == (lhs: Self, rhs: Self) -> Bool { + lhs.storage == rhs.storage + } +} + +// MARK: - Comparable + +extension UInt14 /*: Comparable */ { + public static func < (lhs: Self, rhs: Self) -> Bool { + lhs.storage < rhs.storage + } +} + +// MARK: - Hashable + +extension UInt14 /*: Hashable */ { + public func hash(into hasher: inout Hasher) { + hasher.combine(storage) + } +} + +// MARK: - Codable + +extension UInt14 /*: Codable */ { + public func encode(to encoder: Encoder) throws { + var e = encoder.singleValueContainer() + try e.encode(storage) + } + + public init(from decoder: Decoder) throws { + let d = try decoder.singleValueContainer() + let decoded = try d.decode(Storage.self) + guard let new = Self(exactly: decoded) else { + throw DecodingError.dataCorrupted( + .init(codingPath: decoder.codingPath, + debugDescription: "Encoded value is not a valid \(Self.integerName).") + ) + } + self = new + } +} + +// MARK: - CustomStringConvertible + +extension UInt14 {//: CustomStringConvertible, CustomDebugStringConvertible { + public var description: String { + storage.description + } + + public var debugDescription: String { + "\(Self.integerName)(\(storage.description))" + } +} + +// MARK: - _MIDIUnsignedInteger Default Implementation + +extension UInt14 { + static func min(as ofType: T.Type) -> T { 0 } + static func min(as ofType: T.Type) -> T { 0 } + + static func max(as ofType: T.Type) -> T { + (0 ..< bitWidth) + .reduce(into: T()) { $0 |= (0b1 << $1) } + } + + static func max(as ofType: T.Type) -> T { + T(max(as: Int.self)) + } +} + +// MARK: - MIDIUnsignedInteger Conveniences + +extension UInt14 { + /// Returns the integer converted to an `Int` instance (convenience). + public var intValue: Int { Int(storage) } +} + +// MARK: - FixedWidthInteger + +extension UInt14 /*: FixedWidthInteger */ { + public static var min: Self { Self(Self.min(as: Storage.self)) } + + public static var max: Self { Self(Self.max(as: Storage.self)) } + + // this would be synthesized if MIDIUnsignedInteger conformed to FixedWidthInteger + public static func >>= (lhs: inout Self, rhs: RHS) where RHS : BinaryInteger { + lhs.storage >>= rhs + } + + // this would be synthesized if MIDIUnsignedInteger conformed to FixedWidthInteger + public static func <<= (lhs: inout Self, rhs: RHS) where RHS : BinaryInteger { + lhs.storage <<= rhs + } +} + +// MARK: - Numeric + +extension UInt14 /*: Numeric */ { + // public typealias Magnitude = Storage.Magnitude + // Magnitude is already expressed as same-type constraint on MIDIUnsignedInteger + + public var magnitude: Storage.Magnitude { + storage.magnitude + } + + public init?(exactly source: T) where T: BinaryInteger { + if source < Self.min(as: Storage.self) || + source > Self.max(as: Storage.self) + { + return nil + } + self.init(unchecked: Storage(source)) + } + + public static func * (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage * rhs.storage) + } + + public static func *= (lhs: inout Self, rhs: Self) { + lhs = Self(lhs.storage * rhs.storage) + } +} + +// MARK: - AdditiveArithmetic + +extension UInt14 /*: AdditiveArithmetic */ { + // static let zero synthesized by AdditiveArithmetic + + public static func + (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage + rhs.storage) + } + + // += operator synthesized by AdditiveArithmetic + + public static func - (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage - rhs.storage) + } + + // -= operator synthesized by AdditiveArithmetic +} + +// MARK: - BinaryInteger + +extension UInt14 /*: BinaryInteger */ { + // public typealias Words = Storage.Words + // Words is already expressed as same-type constraint on MIDIUnsignedInteger + + public var words: Storage.Words { + storage.words + } + + // synthesized? + // public static var isSigned: Bool { false } + + public var bitWidth: Int { Self.bitWidth } + + public var trailingZeroBitCount: Int { + storage.trailingZeroBitCount - (storage.bitWidth - Self.bitWidth) + } + + public static func / (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage / rhs.storage) + } + + public static func /= (lhs: inout Self, rhs: Self) { + lhs = Self(lhs.storage / rhs.storage) + } + + public static func % (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage % rhs.storage) + } + + public static func << (lhs: Self, rhs: RHS) -> Self + where RHS: BinaryInteger { + Self(lhs.storage << rhs) + } + + public static func >> (lhs: Self, rhs: RHS) -> Self + where RHS: BinaryInteger { + Self(lhs.storage >> rhs) + } + + public static func %= (lhs: inout Self, rhs: Self) { + lhs.storage %= rhs.storage + } + + public static func &= (lhs: inout Self, rhs: Self) { + lhs.storage &= rhs.storage + } + + public static func |= (lhs: inout Self, rhs: Self) { + lhs.storage |= rhs.storage + } + + public static func ^= (lhs: inout Self, rhs: Self) { + lhs.storage ^= rhs.storage + } + + public static prefix func ~ (x: Self) -> Self { + // mask to bit width + Self(unchecked: ~x.storage & Self.max(as: Self.self).storage) + } +} diff --git a/Sources/MIDIKitCore/Types/UInt25.swift b/Sources/MIDIKitCore/Types/UInt25.swift index 0ffec15395..afe2813b9a 100644 --- a/Sources/MIDIKitCore/Types/UInt25.swift +++ b/Sources/MIDIKitCore/Types/UInt25.swift @@ -32,14 +32,6 @@ extension UInt25 { public static let bitWidth: Int = 25 } -// MARK: - Equatable - -extension UInt25 /*: Equatable */ { - public static func == (lhs: Self, rhs: Self) -> Bool { - lhs.storage == rhs.storage - } -} - // MARK: - Standard library extensions extension BinaryInteger { @@ -77,3 +69,214 @@ extension UInt25 { /// Returns the integer as a `UInt32` instance public var uInt32Value: UInt32 { storage } } + +// ---------------------------------------- +// MARK: - Common Conformances Across UInts +// ---------------------------------------- + +// MARK: - Equatable + +extension UInt25 /*: Equatable */ { + public static func == (lhs: Self, rhs: Self) -> Bool { + lhs.storage == rhs.storage + } +} + +// MARK: - Comparable + +extension UInt25 /*: Comparable */ { + public static func < (lhs: Self, rhs: Self) -> Bool { + lhs.storage < rhs.storage + } +} + +// MARK: - Hashable + +extension UInt25 /*: Hashable */ { + public func hash(into hasher: inout Hasher) { + hasher.combine(storage) + } +} + +// MARK: - Codable + +extension UInt25 /*: Codable */ { + public func encode(to encoder: Encoder) throws { + var e = encoder.singleValueContainer() + try e.encode(storage) + } + + public init(from decoder: Decoder) throws { + let d = try decoder.singleValueContainer() + let decoded = try d.decode(Storage.self) + guard let new = Self(exactly: decoded) else { + throw DecodingError.dataCorrupted( + .init(codingPath: decoder.codingPath, + debugDescription: "Encoded value is not a valid \(Self.integerName).") + ) + } + self = new + } +} + +// MARK: - CustomStringConvertible + +extension UInt25 {//: CustomStringConvertible, CustomDebugStringConvertible { + public var description: String { + storage.description + } + + public var debugDescription: String { + "\(Self.integerName)(\(storage.description))" + } +} + +// MARK: - _MIDIUnsignedInteger Default Implementation + +extension UInt25 { + static func min(as ofType: T.Type) -> T { 0 } + static func min(as ofType: T.Type) -> T { 0 } + + static func max(as ofType: T.Type) -> T { + (0 ..< bitWidth) + .reduce(into: T()) { $0 |= (0b1 << $1) } + } + + static func max(as ofType: T.Type) -> T { + T(max(as: Int.self)) + } +} + +// MARK: - MIDIUnsignedInteger Conveniences + +extension UInt25 { + /// Returns the integer converted to an `Int` instance (convenience). + public var intValue: Int { Int(storage) } +} + +// MARK: - FixedWidthInteger + +extension UInt25 /*: FixedWidthInteger */ { + public static var min: Self { Self(Self.min(as: Storage.self)) } + + public static var max: Self { Self(Self.max(as: Storage.self)) } + + // this would be synthesized if MIDIUnsignedInteger conformed to FixedWidthInteger + public static func >>= (lhs: inout Self, rhs: RHS) where RHS : BinaryInteger { + lhs.storage >>= rhs + } + + // this would be synthesized if MIDIUnsignedInteger conformed to FixedWidthInteger + public static func <<= (lhs: inout Self, rhs: RHS) where RHS : BinaryInteger { + lhs.storage <<= rhs + } +} + +// MARK: - Numeric + +extension UInt25 /*: Numeric */ { + // public typealias Magnitude = Storage.Magnitude + // Magnitude is already expressed as same-type constraint on MIDIUnsignedInteger + + public var magnitude: Storage.Magnitude { + storage.magnitude + } + + public init?(exactly source: T) where T: BinaryInteger { + if source < Self.min(as: Storage.self) || + source > Self.max(as: Storage.self) + { + return nil + } + self.init(unchecked: Storage(source)) + } + + public static func * (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage * rhs.storage) + } + + public static func *= (lhs: inout Self, rhs: Self) { + lhs = Self(lhs.storage * rhs.storage) + } +} + +// MARK: - AdditiveArithmetic + +extension UInt25 /*: AdditiveArithmetic */ { + // static let zero synthesized by AdditiveArithmetic + + public static func + (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage + rhs.storage) + } + + // += operator synthesized by AdditiveArithmetic + + public static func - (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage - rhs.storage) + } + + // -= operator synthesized by AdditiveArithmetic +} + +// MARK: - BinaryInteger + +extension UInt25 /*: BinaryInteger */ { + // public typealias Words = Storage.Words + // Words is already expressed as same-type constraint on MIDIUnsignedInteger + + public var words: Storage.Words { + storage.words + } + + // synthesized? + // public static var isSigned: Bool { false } + + public var bitWidth: Int { Self.bitWidth } + + public var trailingZeroBitCount: Int { + storage.trailingZeroBitCount - (storage.bitWidth - Self.bitWidth) + } + + public static func / (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage / rhs.storage) + } + + public static func /= (lhs: inout Self, rhs: Self) { + lhs = Self(lhs.storage / rhs.storage) + } + + public static func % (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage % rhs.storage) + } + + public static func << (lhs: Self, rhs: RHS) -> Self + where RHS: BinaryInteger { + Self(lhs.storage << rhs) + } + + public static func >> (lhs: Self, rhs: RHS) -> Self + where RHS: BinaryInteger { + Self(lhs.storage >> rhs) + } + + public static func %= (lhs: inout Self, rhs: Self) { + lhs.storage %= rhs.storage + } + + public static func &= (lhs: inout Self, rhs: Self) { + lhs.storage &= rhs.storage + } + + public static func |= (lhs: inout Self, rhs: Self) { + lhs.storage |= rhs.storage + } + + public static func ^= (lhs: inout Self, rhs: Self) { + lhs.storage ^= rhs.storage + } + + public static prefix func ~ (x: Self) -> Self { + // mask to bit width + Self(unchecked: ~x.storage & Self.max(as: Self.self).storage) + } +} diff --git a/Sources/MIDIKitCore/Types/UInt4.swift b/Sources/MIDIKitCore/Types/UInt4.swift index 35517801ed..a723efa8d7 100644 --- a/Sources/MIDIKitCore/Types/UInt4.swift +++ b/Sources/MIDIKitCore/Types/UInt4.swift @@ -32,14 +32,6 @@ extension UInt4 { public static let bitWidth: Int = 4 } -// MARK: - Equatable - -extension UInt4 /*: Equatable */ { - public static func == (lhs: Self, rhs: Self) -> Bool { - lhs.storage == rhs.storage - } -} - // MARK: - Standard library extensions extension BinaryInteger { @@ -72,3 +64,214 @@ extension UInt4 { /// Returns the integer as a `UInt8` instance. public var uInt8Value: UInt8 { storage } } + +// ---------------------------------------- +// MARK: - Common Conformances Across UInts +// ---------------------------------------- + +// MARK: - Equatable + +extension UInt4 /*: Equatable */ { + public static func == (lhs: Self, rhs: Self) -> Bool { + lhs.storage == rhs.storage + } +} + +// MARK: - Comparable + +extension UInt4 /*: Comparable */ { + public static func < (lhs: Self, rhs: Self) -> Bool { + lhs.storage < rhs.storage + } +} + +// MARK: - Hashable + +extension UInt4 /*: Hashable */ { + public func hash(into hasher: inout Hasher) { + hasher.combine(storage) + } +} + +// MARK: - Codable + +extension UInt4 /*: Codable */ { + public func encode(to encoder: Encoder) throws { + var e = encoder.singleValueContainer() + try e.encode(storage) + } + + public init(from decoder: Decoder) throws { + let d = try decoder.singleValueContainer() + let decoded = try d.decode(Storage.self) + guard let new = Self(exactly: decoded) else { + throw DecodingError.dataCorrupted( + .init(codingPath: decoder.codingPath, + debugDescription: "Encoded value is not a valid \(Self.integerName).") + ) + } + self = new + } +} + +// MARK: - CustomStringConvertible + +extension UInt4 {//: CustomStringConvertible, CustomDebugStringConvertible { + public var description: String { + storage.description + } + + public var debugDescription: String { + "\(Self.integerName)(\(storage.description))" + } +} + +// MARK: - _MIDIUnsignedInteger Default Implementation + +extension UInt4 { + static func min(as ofType: T.Type) -> T { 0 } + static func min(as ofType: T.Type) -> T { 0 } + + static func max(as ofType: T.Type) -> T { + (0 ..< bitWidth) + .reduce(into: T()) { $0 |= (0b1 << $1) } + } + + static func max(as ofType: T.Type) -> T { + T(max(as: Int.self)) + } +} + +// MARK: - MIDIUnsignedInteger Conveniences + +extension UInt4 { + /// Returns the integer converted to an `Int` instance (convenience). + public var intValue: Int { Int(storage) } +} + +// MARK: - FixedWidthInteger + +extension UInt4 /*: FixedWidthInteger */ { + public static var min: Self { Self(Self.min(as: Storage.self)) } + + public static var max: Self { Self(Self.max(as: Storage.self)) } + + // this would be synthesized if MIDIUnsignedInteger conformed to FixedWidthInteger + public static func >>= (lhs: inout Self, rhs: RHS) where RHS : BinaryInteger { + lhs.storage >>= rhs + } + + // this would be synthesized if MIDIUnsignedInteger conformed to FixedWidthInteger + public static func <<= (lhs: inout Self, rhs: RHS) where RHS : BinaryInteger { + lhs.storage <<= rhs + } +} + +// MARK: - Numeric + +extension UInt4 /*: Numeric */ { + // public typealias Magnitude = Storage.Magnitude + // Magnitude is already expressed as same-type constraint on MIDIUnsignedInteger + + public var magnitude: Storage.Magnitude { + storage.magnitude + } + + public init?(exactly source: T) where T: BinaryInteger { + if source < Self.min(as: Storage.self) || + source > Self.max(as: Storage.self) + { + return nil + } + self.init(unchecked: Storage(source)) + } + + public static func * (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage * rhs.storage) + } + + public static func *= (lhs: inout Self, rhs: Self) { + lhs = Self(lhs.storage * rhs.storage) + } +} + +// MARK: - AdditiveArithmetic + +extension UInt4 /*: AdditiveArithmetic */ { + // static let zero synthesized by AdditiveArithmetic + + public static func + (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage + rhs.storage) + } + + // += operator synthesized by AdditiveArithmetic + + public static func - (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage - rhs.storage) + } + + // -= operator synthesized by AdditiveArithmetic +} + +// MARK: - BinaryInteger + +extension UInt4 /*: BinaryInteger */ { + // public typealias Words = Storage.Words + // Words is already expressed as same-type constraint on MIDIUnsignedInteger + + public var words: Storage.Words { + storage.words + } + + // synthesized? + // public static var isSigned: Bool { false } + + public var bitWidth: Int { Self.bitWidth } + + public var trailingZeroBitCount: Int { + storage.trailingZeroBitCount - (storage.bitWidth - Self.bitWidth) + } + + public static func / (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage / rhs.storage) + } + + public static func /= (lhs: inout Self, rhs: Self) { + lhs = Self(lhs.storage / rhs.storage) + } + + public static func % (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage % rhs.storage) + } + + public static func << (lhs: Self, rhs: RHS) -> Self + where RHS: BinaryInteger { + Self(lhs.storage << rhs) + } + + public static func >> (lhs: Self, rhs: RHS) -> Self + where RHS: BinaryInteger { + Self(lhs.storage >> rhs) + } + + public static func %= (lhs: inout Self, rhs: Self) { + lhs.storage %= rhs.storage + } + + public static func &= (lhs: inout Self, rhs: Self) { + lhs.storage &= rhs.storage + } + + public static func |= (lhs: inout Self, rhs: Self) { + lhs.storage |= rhs.storage + } + + public static func ^= (lhs: inout Self, rhs: Self) { + lhs.storage ^= rhs.storage + } + + public static prefix func ~ (x: Self) -> Self { + // mask to bit width + Self(unchecked: ~x.storage & Self.max(as: Self.self).storage) + } +} diff --git a/Sources/MIDIKitCore/Types/UInt7.swift b/Sources/MIDIKitCore/Types/UInt7.swift index 0387e81542..bccd8f50fd 100644 --- a/Sources/MIDIKitCore/Types/UInt7.swift +++ b/Sources/MIDIKitCore/Types/UInt7.swift @@ -32,14 +32,6 @@ extension UInt7 { public static let bitWidth: Int = 7 } -// MARK: - Equatable - -extension UInt7 /*: Equatable */ { - public static func == (lhs: Self, rhs: Self) -> Bool { - lhs.storage == rhs.storage - } -} - // MARK: - Standard library extensions extension BinaryInteger { @@ -77,3 +69,214 @@ extension UInt7 { /// Returns the integer as a `UInt8` instance. public var uInt8Value: UInt8 { storage } } + +// ---------------------------------------- +// MARK: - Common Conformances Across UInts +// ---------------------------------------- + +// MARK: - Equatable + +extension UInt7 /*: Equatable */ { + public static func == (lhs: Self, rhs: Self) -> Bool { + lhs.storage == rhs.storage + } +} + +// MARK: - Comparable + +extension UInt7 /*: Comparable */ { + public static func < (lhs: Self, rhs: Self) -> Bool { + lhs.storage < rhs.storage + } +} + +// MARK: - Hashable + +extension UInt7 /*: Hashable */ { + public func hash(into hasher: inout Hasher) { + hasher.combine(storage) + } +} + +// MARK: - Codable + +extension UInt7 /*: Codable */ { + public func encode(to encoder: Encoder) throws { + var e = encoder.singleValueContainer() + try e.encode(storage) + } + + public init(from decoder: Decoder) throws { + let d = try decoder.singleValueContainer() + let decoded = try d.decode(Storage.self) + guard let new = Self(exactly: decoded) else { + throw DecodingError.dataCorrupted( + .init(codingPath: decoder.codingPath, + debugDescription: "Encoded value is not a valid \(Self.integerName).") + ) + } + self = new + } +} + +// MARK: - CustomStringConvertible + +extension UInt7 {//: CustomStringConvertible, CustomDebugStringConvertible { + public var description: String { + storage.description + } + + public var debugDescription: String { + "\(Self.integerName)(\(storage.description))" + } +} + +// MARK: - _MIDIUnsignedInteger Default Implementation + +extension UInt7 { + static func min(as ofType: T.Type) -> T { 0 } + static func min(as ofType: T.Type) -> T { 0 } + + static func max(as ofType: T.Type) -> T { + (0 ..< bitWidth) + .reduce(into: T()) { $0 |= (0b1 << $1) } + } + + static func max(as ofType: T.Type) -> T { + T(max(as: Int.self)) + } +} + +// MARK: - MIDIUnsignedInteger Conveniences + +extension UInt7 { + /// Returns the integer converted to an `Int` instance (convenience). + public var intValue: Int { Int(storage) } +} + +// MARK: - FixedWidthInteger + +extension UInt7 /*: FixedWidthInteger */ { + public static var min: Self { Self(Self.min(as: Storage.self)) } + + public static var max: Self { Self(Self.max(as: Storage.self)) } + + // this would be synthesized if MIDIUnsignedInteger conformed to FixedWidthInteger + public static func >>= (lhs: inout Self, rhs: RHS) where RHS : BinaryInteger { + lhs.storage >>= rhs + } + + // this would be synthesized if MIDIUnsignedInteger conformed to FixedWidthInteger + public static func <<= (lhs: inout Self, rhs: RHS) where RHS : BinaryInteger { + lhs.storage <<= rhs + } +} + +// MARK: - Numeric + +extension UInt7 /*: Numeric */ { + // public typealias Magnitude = Storage.Magnitude + // Magnitude is already expressed as same-type constraint on MIDIUnsignedInteger + + public var magnitude: Storage.Magnitude { + storage.magnitude + } + + public init?(exactly source: T) where T: BinaryInteger { + if source < Self.min(as: Storage.self) || + source > Self.max(as: Storage.self) + { + return nil + } + self.init(unchecked: Storage(source)) + } + + public static func * (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage * rhs.storage) + } + + public static func *= (lhs: inout Self, rhs: Self) { + lhs = Self(lhs.storage * rhs.storage) + } +} + +// MARK: - AdditiveArithmetic + +extension UInt7 /*: AdditiveArithmetic */ { + // static let zero synthesized by AdditiveArithmetic + + public static func + (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage + rhs.storage) + } + + // += operator synthesized by AdditiveArithmetic + + public static func - (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage - rhs.storage) + } + + // -= operator synthesized by AdditiveArithmetic +} + +// MARK: - BinaryInteger + +extension UInt7 /*: BinaryInteger */ { + // public typealias Words = Storage.Words + // Words is already expressed as same-type constraint on MIDIUnsignedInteger + + public var words: Storage.Words { + storage.words + } + + // synthesized? + // public static var isSigned: Bool { false } + + public var bitWidth: Int { Self.bitWidth } + + public var trailingZeroBitCount: Int { + storage.trailingZeroBitCount - (storage.bitWidth - Self.bitWidth) + } + + public static func / (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage / rhs.storage) + } + + public static func /= (lhs: inout Self, rhs: Self) { + lhs = Self(lhs.storage / rhs.storage) + } + + public static func % (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage % rhs.storage) + } + + public static func << (lhs: Self, rhs: RHS) -> Self + where RHS: BinaryInteger { + Self(lhs.storage << rhs) + } + + public static func >> (lhs: Self, rhs: RHS) -> Self + where RHS: BinaryInteger { + Self(lhs.storage >> rhs) + } + + public static func %= (lhs: inout Self, rhs: Self) { + lhs.storage %= rhs.storage + } + + public static func &= (lhs: inout Self, rhs: Self) { + lhs.storage &= rhs.storage + } + + public static func |= (lhs: inout Self, rhs: Self) { + lhs.storage |= rhs.storage + } + + public static func ^= (lhs: inout Self, rhs: Self) { + lhs.storage ^= rhs.storage + } + + public static prefix func ~ (x: Self) -> Self { + // mask to bit width + Self(unchecked: ~x.storage & Self.max(as: Self.self).storage) + } +} diff --git a/Sources/MIDIKitCore/Types/UInt9.swift b/Sources/MIDIKitCore/Types/UInt9.swift index b82085f24a..978b116ee4 100644 --- a/Sources/MIDIKitCore/Types/UInt9.swift +++ b/Sources/MIDIKitCore/Types/UInt9.swift @@ -32,14 +32,6 @@ extension UInt9 { public static let bitWidth: Int = 9 } -// MARK: - Equatable - -extension UInt9 /*: Equatable */ { - public static func == (lhs: Self, rhs: Self) -> Bool { - lhs.storage == rhs.storage - } -} - // MARK: - Standard library extensions extension BinaryInteger { @@ -75,3 +67,214 @@ extension UInt9 { /// Returns the integer as a `UInt16` instance. public var uInt16Value: UInt16 { storage } } + +// ---------------------------------------- +// MARK: - Common Conformances Across UInts +// ---------------------------------------- + +// MARK: - Equatable + +extension UInt9 /*: Equatable */ { + public static func == (lhs: Self, rhs: Self) -> Bool { + lhs.storage == rhs.storage + } +} + +// MARK: - Comparable + +extension UInt9 /*: Comparable */ { + public static func < (lhs: Self, rhs: Self) -> Bool { + lhs.storage < rhs.storage + } +} + +// MARK: - Hashable + +extension UInt9 /*: Hashable */ { + public func hash(into hasher: inout Hasher) { + hasher.combine(storage) + } +} + +// MARK: - Codable + +extension UInt9 /*: Codable */ { + public func encode(to encoder: Encoder) throws { + var e = encoder.singleValueContainer() + try e.encode(storage) + } + + public init(from decoder: Decoder) throws { + let d = try decoder.singleValueContainer() + let decoded = try d.decode(Storage.self) + guard let new = Self(exactly: decoded) else { + throw DecodingError.dataCorrupted( + .init(codingPath: decoder.codingPath, + debugDescription: "Encoded value is not a valid \(Self.integerName).") + ) + } + self = new + } +} + +// MARK: - CustomStringConvertible + +extension UInt9 {//: CustomStringConvertible, CustomDebugStringConvertible { + public var description: String { + storage.description + } + + public var debugDescription: String { + "\(Self.integerName)(\(storage.description))" + } +} + +// MARK: - _MIDIUnsignedInteger Default Implementation + +extension UInt9 { + static func min(as ofType: T.Type) -> T { 0 } + static func min(as ofType: T.Type) -> T { 0 } + + static func max(as ofType: T.Type) -> T { + (0 ..< bitWidth) + .reduce(into: T()) { $0 |= (0b1 << $1) } + } + + static func max(as ofType: T.Type) -> T { + T(max(as: Int.self)) + } +} + +// MARK: - MIDIUnsignedInteger Conveniences + +extension UInt9 { + /// Returns the integer converted to an `Int` instance (convenience). + public var intValue: Int { Int(storage) } +} + +// MARK: - FixedWidthInteger + +extension UInt9 /*: FixedWidthInteger */ { + public static var min: Self { Self(Self.min(as: Storage.self)) } + + public static var max: Self { Self(Self.max(as: Storage.self)) } + + // this would be synthesized if MIDIUnsignedInteger conformed to FixedWidthInteger + public static func >>= (lhs: inout Self, rhs: RHS) where RHS : BinaryInteger { + lhs.storage >>= rhs + } + + // this would be synthesized if MIDIUnsignedInteger conformed to FixedWidthInteger + public static func <<= (lhs: inout Self, rhs: RHS) where RHS : BinaryInteger { + lhs.storage <<= rhs + } +} + +// MARK: - Numeric + +extension UInt9 /*: Numeric */ { + // public typealias Magnitude = Storage.Magnitude + // Magnitude is already expressed as same-type constraint on MIDIUnsignedInteger + + public var magnitude: Storage.Magnitude { + storage.magnitude + } + + public init?(exactly source: T) where T: BinaryInteger { + if source < Self.min(as: Storage.self) || + source > Self.max(as: Storage.self) + { + return nil + } + self.init(unchecked: Storage(source)) + } + + public static func * (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage * rhs.storage) + } + + public static func *= (lhs: inout Self, rhs: Self) { + lhs = Self(lhs.storage * rhs.storage) + } +} + +// MARK: - AdditiveArithmetic + +extension UInt9 /*: AdditiveArithmetic */ { + // static let zero synthesized by AdditiveArithmetic + + public static func + (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage + rhs.storage) + } + + // += operator synthesized by AdditiveArithmetic + + public static func - (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage - rhs.storage) + } + + // -= operator synthesized by AdditiveArithmetic +} + +// MARK: - BinaryInteger + +extension UInt9 /*: BinaryInteger */ { + // public typealias Words = Storage.Words + // Words is already expressed as same-type constraint on MIDIUnsignedInteger + + public var words: Storage.Words { + storage.words + } + + // synthesized? + // public static var isSigned: Bool { false } + + public var bitWidth: Int { Self.bitWidth } + + public var trailingZeroBitCount: Int { + storage.trailingZeroBitCount - (storage.bitWidth - Self.bitWidth) + } + + public static func / (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage / rhs.storage) + } + + public static func /= (lhs: inout Self, rhs: Self) { + lhs = Self(lhs.storage / rhs.storage) + } + + public static func % (lhs: Self, rhs: Self) -> Self { + Self(lhs.storage % rhs.storage) + } + + public static func << (lhs: Self, rhs: RHS) -> Self + where RHS: BinaryInteger { + Self(lhs.storage << rhs) + } + + public static func >> (lhs: Self, rhs: RHS) -> Self + where RHS: BinaryInteger { + Self(lhs.storage >> rhs) + } + + public static func %= (lhs: inout Self, rhs: Self) { + lhs.storage %= rhs.storage + } + + public static func &= (lhs: inout Self, rhs: Self) { + lhs.storage &= rhs.storage + } + + public static func |= (lhs: inout Self, rhs: Self) { + lhs.storage |= rhs.storage + } + + public static func ^= (lhs: inout Self, rhs: Self) { + lhs.storage ^= rhs.storage + } + + public static prefix func ~ (x: Self) -> Self { + // mask to bit width + Self(unchecked: ~x.storage & Self.max(as: Self.self).storage) + } +}