#core #currencies #formatting #currencies-core

no-std currencies-core

core types for the currencies crate

2 releases

0.4.1 Jun 21, 2024
0.4.0 Jun 5, 2024

#1621 in Math

Download history 91/week @ 2024-12-25 264/week @ 2025-01-01 312/week @ 2025-01-08 328/week @ 2025-01-15 469/week @ 2025-01-22 355/week @ 2025-01-29 296/week @ 2025-02-05 383/week @ 2025-02-12 405/week @ 2025-02-19 230/week @ 2025-02-26 337/week @ 2025-03-05 316/week @ 2025-03-12 120/week @ 2025-03-19 132/week @ 2025-03-26 182/week @ 2025-04-02 187/week @ 2025-04-09

664 downloads per month
Used in 2 crates

MIT license

64KB
1.5K SLoC

💰 currencies

Crates.io docs.rs Build Status MIT License

This crate provides a generic Currency and corresponding Amount type that can handle basic arithmetic operations and formatting of arbitrary currencies and cryptocurrencies. Main features include:

Features

  • Built-in support for all ISO-4217 currencies with proper precision and formatting
  • Support for a variety of cryptocurrencies, also with proper underlying data types and formatting. Accurate implementations for ETH, BTC, DOT, and a variety of other cryptocurrencies are included.
  • The ability to specify whether an Amount is forced to only make use of unchecked math, or not, at compile-time. Normally this is impossible to control since the core:ops operators are set up such that the checked operators require their unchecked counterparts to be implemented on the host type, however I have gone out of my way to make it possible to implement unchecked math only, and control it easily with a Amount<ETH, Checked>-style switch. This is extremely desirable for scenarios where panicking could cause a catastrophic issue, and the way it is set up, programmers are forced to consume the Option returned by the checked ops.
  • An easy-to-use macro, define_currency! that can define new currencies on-the-fly.
  • A painstakingly wrapped version of primitive_types::U256 that implements many more useful num-traits and num-integer traits than what Parity includes with the num-traits feature, and are often required when working with amounts of a currency.
  • All provided currencies implement most useful num-traits and num-integer traits.
  • Thorough testing of all of the above.

Examples

#[test]
fn show_off_currency_math() {
    use currency::*;

    let apple_cost = amt!(USD, "$3.24");
    let orange_cost = Amount::<USD>::from_raw(7_97);
    assert!(apple_cost < orange_cost);
    assert!(apple_cost + orange_cost > orange_cost);
    assert_eq!(format!("{}", apple_cost * orange_cost), "$25.82");
    assert_eq!(format!("{}", apple_cost * 3), "$9.72");

    let mut total = amt!(DOT, "57622449841.0000000004 DOT");
    total -= amt!(DOT, "1000.0 DOT");
    total *= Amount::from_raw(2_0000000000u64.into());
    assert_eq!(format!("{}", total), "115244897682.0000000008 DOT");
}

#[test]
fn show_off_checked_math() {
    use currency::*;
    use safety::*;

    // When using currency amounts with `Safety = Checked`, the Amount struct has been specially set
    // up so that only checked math will be allowed, and you can still use the normal
    // operator-based syntax. Thus currency amounts like this should never panic and are
    // suitable for use in critical/infallible environments.
    let drink_cost = amt_checked!(USD, "$6.29");
    let movie_cost = Amount::<USD, Checked>::from_raw(24_99);
    let Some(outing_cost) = drink_cost + movie_cost else {
      unimplemented!("compiler forces you to handle this!")
    };
    assert_eq!(format!("{}", outing_cost), "$31.28");
}

Future Work

  • Additional macros for defining an Amount via a decimal literal
  • Currency conversion facilities, possibly including an online data source
  • Add Signedness support to Amount
  • Additional testing
  • Support for negative amounts via an additional const generic defaulting to Positive

Dependencies

~0.4–1.2MB
~22K SLoC