Files
purchases-ios/Sources/LocalReceiptParsing/DataConverters/UInt8+Extensions.swift
T

81 lines
2.1 KiB
Swift

//
// Copyright RevenueCat Inc. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// UInt8+Extensions.swift
//
// Created by Andrés Boedo on 7/24/20.
//
import Foundation
// swiftlint:disable identifier_name
enum BitShiftError: Error {
case invalidIndex(_ index: UInt8)
case rangeFlipped(from: UInt8, to: UInt8)
case rangeLargerThanByte
case unhandledRange
}
extension BitShiftError: CustomStringConvertible {
var description: String {
switch self {
case .invalidIndex(let index):
return "invalid index: \(index)"
case .rangeFlipped(let from, let to):
return "from: \(from) can't be greater than to: \(to)"
case .rangeLargerThanByte:
return "range must be between 1 and 8"
case .unhandledRange:
return "unhandled range"
}
}
}
extension UInt8 {
/// - Throws: `BitShiftError`
func bitAtIndex(_ index: UInt8) throws -> UInt8 {
guard index <= 7 else { throw BitShiftError.invalidIndex(index) }
let shifted = self >> (7 - index)
return shifted & 0b1
}
/// - Throws: `BitShiftError`
func valueInRange(from: UInt8, to: UInt8) throws -> UInt8 {
guard to <= 7 else { throw BitShiftError.invalidIndex(to) }
guard from <= to else { throw BitShiftError.rangeFlipped(from: from, to: to) }
let range: UInt8 = to - from + 1
let shifted = self >> (7 - to)
let mask = try self.maskForRange(range)
return shifted & mask
}
}
private extension UInt8 {
/// - Returns: 2^range - 1
/// - Throws: `BitShiftError`
func maskForRange(_ range: UInt8) throws -> UInt8 {
guard 0 <= range && range <= 8 else { throw BitShiftError.rangeLargerThanByte }
/// Returns 2 ^ range - 1 (a number with range 1s)
/// Example:
/// - range 1: 0b1
/// - range 2: 0b11
return 0b11111111 >> (8 - range)
}
}