Skip to content

Instantly share code, notes, and snippets.

@st-small
Last active April 10, 2019 12:11
Show Gist options
  • Save st-small/866d701c988158b976c7409ceebd31b0 to your computer and use it in GitHub Desktop.
Save st-small/866d701c988158b976c7409ceebd31b0 to your computer and use it in GitHub Desktop.
Phantom types
import UIKit
protocol Currency {
static var code: String { get }
static var factor: NSDecimalNumber { get }
}
enum USD: Currency {
static let code = "USD"
static let factor: NSDecimalNumber = 1.0
}
enum RUB: Currency {
static let code = "RUB"
static let factor: NSDecimalNumber = 65.74
}
enum UAH: Currency {
static let code = "UAH"
static let factor: NSDecimalNumber = 26.95
}
struct Money<Cur: Currency>: CustomStringConvertible, ExpressibleByFloatLiteral, ExpressibleByIntegerLiteral {
let amount: NSDecimalNumber
var description: String {
let f = NumberFormatter()
f.numberStyle = .currency
f.currencyCode = Cur.code
return f.string(from: self.amount)!
}
init(floatLiteral value: Double) {
self.amount = NSDecimalNumber(value: value)
}
init(integerLiteral value: Int) {
self.amount = NSDecimalNumber(value: value)
}
init(_ amount: NSDecimalNumber) {
self.amount = amount
}
func convertTo<C: Currency>() -> Money<C> {
let baseAmount = amount.multiplying(by: Cur.factor)
let convertedAmount = baseAmount.multiplying(by: C.factor)
return Money<C>(convertedAmount)
}
}
extension Money {
var usd: Money<USD> { return convertTo() }
var rub: Money<RUB> { return convertTo() }
var uah: Money<UAH> { return convertTo() }
}
// Usage
let cocaCola: Money<USD> = 2.44
print(cocaCola.usd)
print(cocaCola.rub)
print(cocaCola.uah)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment