Help/announcement merx: let you define decimal safe types

Hi All! I released a "pre-beta" version of merx: a crate that let you define typed wrappers around a numeric type, for now the inner numeric value is a dummy internal fixed but I want to make the API generic over the inner type.

here the github rep, here the crate

Merx expose Asset a wrapper around a Debt or a Credit that are wrapper around a numeric value.

pub struct <T: NUMERIC>Debt(T); 
pub struct <T: NUMERIC>Credit(T);
pub enum Asset<T: NUMERIC> {
    Debt(Debt(T)),
    Credit(Credit(T)),
}

The permitted operations are: Credit - Debt , Credit + Credit , Debt + Credit , Debt + Debt and Asset + Asset . Because Credit can not own a negative value, Debt can not own a positive value and Asset is either a Credit or a Debt , is not clear what addition and subtraction between assets means in my opinion the possibilities that make more sense are:

  1. only add(A, B) exist:
    Asset(x) + Asset(-y) = Asset(x + (-y))
  2. add(A, B) == sub(A, B)
    Asset(x) + Asset(-y) = Asset(x + (-y)) && Asset(x) - Asset(-y) = Asset(x + (-y))
  3. add(A, B) == sub(A, -B)
    Asset(x) + Asset(-y) = Asset(x + (-y)) && Asset(x) - Asset(-y) = Asset(x - (-y))

For the moment add and sub behave like (1), because I think that is the less error prone behavior and the merx main goal is safety, by the way usability is also important and I think that (1) is not very usable.

Defining an assets is pretty straightforward:

#[macro_use]
extern crate merx;
use merx::{Asset, Debt, Credit};

get_traits!();

// Create a new asset called bitcoin with 8 decimal digits and a max value of 21 million of units
new_asset!(bitcoin, 8, 21_000_000);
type Bitcoin = Asset<bitcoin::Value>;

After that you can instantiate new asstes of the defined type and do basic operations between them:

// A tuple that define a decimal value as (value, how far from the right the decimal point is)
let tot_amount = (679, 1); // -> 67.9
let tot_amount = Bitcoin::try_from(tot_amount).ok()?;
// You can create an `Asset` from an int
let to_pay = Bitcoin::try_from(-29).ok()?;
let remain = (tot_amount + to_pay)?;

When you define an asset an inner type of 4 8 or 16 bytes is selected based on the asset precision and the asset max value.

I think that the library is pretty fast, I tried to benchmark it but I'm not very sure about the results that I get. For example when we do asset1 + asset2 internally the library do a checked_add and then check if the result is smaller than the max value defined for the asset, the strange thing is that from the benchmarks it seems that doing asset1 + asset2 is faster than doing the same think with a plain function

This is my first library so I would love to know what to you think of the library (good, if there are, and bad things). Praticulary the usefulness of the library, the usability and safety of the API ecc ecc
Also I would really appreciate if someone can review the benchmarks, and of course any advice in general.

Ty :slight_smile:

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.