Browse Source

Simplify exchange_rate handling

David Peter 2 năm trước cách đây
mục cha
commit
3e65abff7e
3 tập tin đã thay đổi với 33 bổ sung37 xóa
  1. 13 20
      numbat/modules/units/currencies.nbt
  2. 2 0
      numbat/modules/units/currency.nbt
  3. 18 17
      numbat/src/ffi.rs

+ 13 - 20
numbat/modules/units/currencies.nbt

@@ -1,37 +1,30 @@
 use core::scalar
 use units::currency
 
-# This module is currently not part of the prelude, because the 'exchange_rate_XXX' calls
-# are blocking. In the CLI application, we do however load this module asynchronously after
-# prefetching the exchange rates.
-
-# TODO: once we support strings as function parameters, use 'exchange_rate("USD")' and
-# similar instead of separate functions.
-fn exchange_rate_USD() -> Scalar
-fn exchange_rate_JPY() -> Scalar
-fn exchange_rate_GBP() -> Scalar
-fn exchange_rate_CNY() -> Scalar
-fn exchange_rate_AUD() -> Scalar
-fn exchange_rate_CAD() -> Scalar
-fn exchange_rate_CHF() -> Scalar
+# This module is currently not part of the prelude, because the 'exchange_rate("XYZ")' calls
+# are blocking. For the CLI application, we do however load this module on demand if one of
+# the identifiers below is. For the Web version, we asynchronously load exchange rates and then
+# pull in this module.
+
+fn exchange_rate(currency: str) -> Scalar
 
 @aliases(dollars, USD, $: short)
-unit dollar: Money = EUR / exchange_rate_USD()
+unit dollar: Money = EUR / exchange_rate("USD")
 
 @aliases(yens, JPY, ¥: short, 円)
-unit yen: Money = EUR / exchange_rate_JPY()
+unit yen: Money = EUR / exchange_rate("JPY")
 
 @aliases(pound_sterling, GBP, £: short)
-unit british_pound: Money = EUR / exchange_rate_GBP()
+unit british_pound: Money = EUR / exchange_rate("GBP")
 
 @aliases(CNY: short, 元)
-unit renminbi: Money = EUR / exchange_rate_CNY()
+unit renminbi: Money = EUR / exchange_rate("CNY")
 
 @aliases(australian_dollars, AUD: short, A$)
-unit australian_dollar: Money = EUR / exchange_rate_AUD()
+unit australian_dollar: Money = EUR / exchange_rate("AUD")
 
 @aliases(canadian_dollars, CAD: short, C$)
-unit canadian_dollar: Money = EUR / exchange_rate_CAD()
+unit canadian_dollar: Money = EUR / exchange_rate("CAD")
 
 @aliases(swiss_francs, CHF: short)
-unit swiss_franc: Money = EUR / exchange_rate_CHF()
+unit swiss_franc: Money = EUR / exchange_rate("CHF")

+ 2 - 0
numbat/modules/units/currency.nbt

@@ -2,3 +2,5 @@ dimension Money
 
 @aliases(euros, EUR, €: short)
 unit euro: Money
+
+# See currencies.nbt for non-Euro currencies

+ 18 - 17
numbat/src/ffi.rs

@@ -298,16 +298,14 @@ pub(crate) fn functions() -> &'static HashMap<String, ForeignFunction> {
             },
         );
 
-        for currency in ["USD", "JPY", "GBP", "CNY", "AUD", "CAD", "CHF"] {
-            m.insert(
-                format!("exchange_rate_{currency}"),
-                ForeignFunction {
-                    name: format!("exchange_rate_{currency}"),
-                    arity: 0..=0,
-                    callable: Callable::Function(exchange_rate(currency)),
-                },
-            );
-        }
+        m.insert(
+            format!("exchange_rate"),
+            ForeignFunction {
+                name: "exchange_rate".into(),
+                arity: 1..=1,
+                callable: Callable::Function(Box::new(exchange_rate)),
+            },
+        );
 
         m.insert(
             "str_length".to_string(),
@@ -694,13 +692,16 @@ fn minimum(args: &[Value]) -> Result<Value> {
     )))
 }
 
-fn exchange_rate(rate: &'static str) -> BoxedFunction {
-    Box::new(|_args: &[Value]| -> Result<Value> {
-        let exchange_rates = ExchangeRatesCache::new();
-        Ok(Value::Quantity(Quantity::from_scalar(
-            exchange_rates.get_rate(rate).unwrap_or(f64::NAN),
-        )))
-    })
+fn exchange_rate(args: &[Value]) -> Result<Value> {
+    assert!(args.len() == 1);
+
+    let rate = args[0].unsafe_as_string();
+
+    let exchange_rates = ExchangeRatesCache::new();
+
+    Ok(Value::Quantity(Quantity::from_scalar(
+        exchange_rates.get_rate(rate).unwrap_or(f64::NAN),
+    )))
 }
 
 fn str_length(args: &[Value]) -> Result<Value> {