price.mojo (1874B)
1 from std.collections import Optional 2 3 4 @fieldwise_init 5 struct Price(Copyable, Movable): 6 var state: String 7 var amount: Int 8 var scale: Int 9 var currency: String 10 var basis: String 11 12 13 def known_price( 14 amount: Int, scale: Int, currency: String, basis: String 15 ) raises -> Price: 16 if scale < 0 or scale > 9: 17 raise Error("price scale must be between 0 and 9") 18 if currency.strip() == "": 19 raise Error("known price requires a currency") 20 if basis != "per_unit" and basis != "per_pack" and basis != "per_order": 21 raise Error("price basis must be per_unit, per_pack or per_order") 22 if amount < 0: 23 raise Error("price amount must be non-negative") 24 return Price( 25 state="known", 26 amount=amount, 27 scale=scale, 28 currency=String(currency), 29 basis=String(basis), 30 ) 31 32 33 def unknown_price() -> Price: 34 return Price( 35 state="unknown", amount=0, scale=0, currency="", basis="unknown" 36 ) 37 38 39 def price_is_known(price: Price) -> Bool: 40 return price.state == "known" 41 42 43 def price_compare(left: Price, right: Price) raises -> Int: 44 if not price_is_known(left) or not price_is_known(right): 45 raise Error("cannot compare unknown prices") 46 if left.currency != right.currency: 47 raise Error( 48 "cannot compare prices in different currencies without conversion" 49 ) 50 if left.basis != right.basis: 51 raise Error("cannot compare prices with different bases") 52 var scale = left.scale if left.scale > right.scale else right.scale 53 var left_value = left.amount 54 var right_value = right.amount 55 for _ in range(scale - left.scale): 56 left_value *= 10 57 for _ in range(scale - right.scale): 58 right_value *= 10 59 if left_value < right_value: 60 return -1 61 if left_value > right_value: 62 return 1 63 return 0