Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
import Foundation
protocol Currency { static var sign: String { get } }
enum GBP: Currency { static let sign = "£" }
enum EUR: Currency { static let sign = "" }
enum USD: Currency { static let sign = "$" }
protocol _Money {
associatedtype C: Currency
var amount: NSDecimalNumber { get }
}
struct Money<Cur: Currency>: _Money, CustomStringConvertible, FloatLiteralConvertible, IntegerLiteralConvertible {
typealias C = Cur
let amount: NSDecimalNumber
var description: String { return Cur.sign + String(amount) }
init(floatLiteral value: Double) { self.amount = NSDecimalNumber(double: value) }
init(integerLiteral value: Int) { self.amount = NSDecimalNumber(integer: value) }
init(_ amount: NSDecimalNumber) { self.amount = amount }
}
extension _Money where C == GBP {
var gbp: Money<GBP> { return Money(amount) }
var eur: Money<EUR> { return Money(amount.decimalNumberByMultiplyingBy(1.27)) }
var usd: Money<USD> { return Money(amount.decimalNumberByMultiplyingBy(1.44)) }
}
extension _Money where C == EUR {
var gbp: Money<GBP> { return Money(amount.decimalNumberByMultiplyingBy(0.79)) }
var eur: Money<EUR> { return Money(amount) }
var usd: Money<USD> { return Money(amount.decimalNumberByMultiplyingBy(1.13)) }
}
extension _Money where C == USD {
var gbp: Money<GBP> { return Money(amount.decimalNumberByMultiplyingBy(0.69)) }
var eur: Money<EUR> { return Money(amount.decimalNumberByMultiplyingBy(0.88)) }
var usd: Money<USD> { return Money(amount) }
}
let fivePound: Money<GBP> = 5 // £5
let threeEuro: Money<EUR> = 3 // €3
print(fivePound.eur) // €6.35
print(threeEuro.gbp) // £2.37
@NatashaTheRobot
Copy link

NatashaTheRobot commented Mar 31, 2016

Thanks @oisdk for the initial solution and @davedelong for optimizing it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment