diff --git a/Sources/TunnelKitCore/DataUnit.swift b/Sources/TunnelKitCore/DataUnit.swift new file mode 100644 index 0000000..e09ca41 --- /dev/null +++ b/Sources/TunnelKitCore/DataUnit.swift @@ -0,0 +1,102 @@ +// +// DataUnit.swift +// TunnelKit +// +// Created by Davide De Rosa on 3/30/18. +// Copyright (c) 2022 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of TunnelKit. +// +// TunnelKit is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// TunnelKit is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with TunnelKit. If not, see . +// + +import Foundation + +/// :nodoc: +public enum DataUnit: UInt, CustomStringConvertible { + case byte = 1 + + case kilobyte = 1024 + + case megabyte = 1048576 + + case gigabyte = 1073741824 + + fileprivate var showsDecimals: Bool { + switch self { + case .byte, .kilobyte: + return false + + case .megabyte, .gigabyte: + return true + } + } + + fileprivate var boundary: UInt { + return UInt(0.1 * Double(rawValue)) + } + + // MARK: CustomStringConvertible + + public var description: String { + switch self { + case .byte: + return "B" + + case .kilobyte: + return "kB" + + case .megabyte: + return "MB" + + case .gigabyte: + return "GB" + } + } +} + +/// :nodoc: +extension UInt { + private static let allUnits: [DataUnit] = [ + .gigabyte, + .megabyte, + .kilobyte, + .byte + ] + + public var descriptionAsDataUnit: String { + if self == 0 { + return "0B" + } + for u in Self.allUnits { + if self >= u.boundary { + if !u.showsDecimals { + return "\(self / u.rawValue)\(u)" + } + let count = Double(self) / Double(u.rawValue) + return String(format: "%.2f%@", count, u.description) + } + } + fatalError("Number is negative") + } +} + +/// :nodoc: +extension Int { + public var descriptionAsDataUnit: String { + return UInt(self).descriptionAsDataUnit + } +} diff --git a/Tests/TunnelKitCoreTests/DataManipulationTests.swift b/Tests/TunnelKitCoreTests/DataManipulationTests.swift index fee7038..e7c961d 100644 --- a/Tests/TunnelKitCoreTests/DataManipulationTests.swift +++ b/Tests/TunnelKitCoreTests/DataManipulationTests.swift @@ -82,4 +82,19 @@ class DataManipulationTests: XCTestCase { v.append(Data(hex: "112233")) XCTAssertEqual(v.flatCount, 21) } + + func testDataUnitDescription() { + XCTAssertEqual(0.descriptionAsDataUnit, "0B") + XCTAssertEqual(1.descriptionAsDataUnit, "1B") + XCTAssertEqual(1024.descriptionAsDataUnit, "1kB") + XCTAssertEqual(1025.descriptionAsDataUnit, "1kB") + XCTAssertEqual(548575.descriptionAsDataUnit, "0.52MB") + XCTAssertEqual(1048575.descriptionAsDataUnit, "1.00MB") + XCTAssertEqual(1048576.descriptionAsDataUnit, "1.00MB") + XCTAssertEqual(1048577.descriptionAsDataUnit, "1.00MB") + XCTAssertEqual(600000000.descriptionAsDataUnit, "0.56GB") + XCTAssertEqual(1073741823.descriptionAsDataUnit, "1.00GB") + XCTAssertEqual(1073741824.descriptionAsDataUnit, "1.00GB") + XCTAssertEqual(1073741825.descriptionAsDataUnit, "1.00GB") + } }