Functional Weave
Code in Rust

money.add

Add, subtract and negate monetary amounts, refusing to mix currencies.

1.0.1 · published 2026-10-03 by charlie · Anterra

Pinned by 12 tests, run in TypeScript, Python and Rust.

What it does

Also exports subtractMoney and negateMoney: they are the same group operation and splitting them across three packages would only make them easier to get wrong separately.

1.0.1 adds tests; behaviour unchanged.

For example

  • add_money(£19.99, £0.01) → £20.00 adds pence
  • add_money(£25.00, £0.00) → £25.00 adds zero
  • add_money(£25.00, -£10.00) → £15.00 adds a negative (a credit)

The function

The same function in TypeScript, Python and Rust, pinned by the same tests. Pick your language; the choice follows you around the registry.

pub fn add_money(a: &Money, b: &Money) -> Money
aMoney
bMoney
returnsMoney

Your code names it in one line, in the file that uses it

fune!(money.add@^1);  // then call add_money(…)
impl/rust.rs · 27 lines · open · raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

use super::funejson::Value;  ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one
use super::money_amount::{assert_same_currency, money, money_from_value, money_to_value, Money};  ← from money.amount ^1.0.0 · built alongside by fune

/// # Panics
/// Panics if the two amounts are in different currencies.
pub fn add_money(a: &Money, b: &Money) -> Money {
    assert_same_currency(a, b);
    money(a.minor + b.minor, &a.currency)
}

/// # Panics
/// Panics if the two amounts are in different currencies.
pub fn subtract_money(a: &Money, b: &Money) -> Money {
    assert_same_currency(a, b);
    money(a.minor - b.minor, &a.currency)
}

pub fn negate_money(a: &Money) -> Money {
    money(-a.minor, &a.currency)
}

pub fn fune_vector(args: &[Value]) -> Value {
    money_to_value(&add_money(
        &money_from_value(&args[0]),
        &money_from_value(&args[1]),
    ))
}

Install

fune build

With that line in your source, in a Rust project (language rust in fune.project), fune build resolves it and its 1 dependency, pins them in fune.lock, downloads only the Rust package of each, and builds the code above into your project’s .fune/build, one readable file per capability with a header linking back here. A crate’s build.rs runs it before every compile. Or pin a range in fune.project and build in one step:

fune add money.add
Download for Rust money.add-1.0.1-rust.fune · 4,666 bytes sha256 90b65af1ee2c2af4c05dcb2831a3a6a8edd17d65cefb5ebcfe065929f60db7f0

The manifest, vectors and README with only the Rust implementation. Install it without the registry with fune add ./money.add-1.0.1-rust.fune, or fetch it from a terminal with fune pull money.add@1.0.1:rust.

The whole function, every language, is one file too: money.add-1.0.1.fune, 5,558 bytes, sha256 8cd9bf58cd000b7479fa5e8e95e7e9aaf8742f7615506f2c78c2793ebbe8bd69. It installs into a project of any language.

Customise it in your app

The seams this capability offers. Put a marker directly above a function of your own and fune build wires it into the built code; the package on the registry is not changed, the built file’s header lists it under CUSTOMISED, and fune hooks lists every hook in the project. How hooks work.

before — your function gets the arguments and returns them, changed or not, or throws to refuse the call.

// fune: before money.add

after — your function gets the result and the arguments, and returns the final result.

// fune: after money.add

replace — inside this capability’s code only, calls to a dependency go to your function, with the same signature. Other capabilities that use it are unaffected; write in * to replace it everywhere.

// fune: replace money.amount in money.add

step — your function runs at a numbered point inside the function’s body, receives the in-scope values it names as parameters, and may return replacements. List the points with fune show money.add --steps.

// fune: step money.add after <n|label>

Tests

A version published now needs at least 8 tests for every function, and one that expects the error for each function that throws; the registry refuses it otherwise. fune verify --all runs each case in TypeScript, Python and Rust, and a project runs them again with fune verify. This page lists the cases; it does not run them. The exact JSON is vectors.json.

CaseArgumentsExpected
adds pence £19.99, £0.01 → £20.00
adds zero £25.00, £0.00 → £25.00
adds a negative (a credit) £25.00, -£10.00 → £15.00
mixing currencies is an error £1.00, €1.00 → error: currency mismatch
a credit larger than the amount goes below zero £1.00, -£2.50 → -£1.50
two credits add up to a bigger credit -£3.00, -£2.00 → -£5.00
a credit that cancels the amount exactly is zero £25.00, -£25.00 → £0.00
zero-decimal currency ¥1,500, ¥2,500 → ¥4,000
up to the largest safe integer, exactly £90,071,992,547,409.90, £0.01 → £90,071,992,547,409.91
mixed currencies are refused even when both are zero £0.00, €0.00 → error: currency mismatch
Show the other 2 tests
CaseArgumentsExpected
currency codes are compared exactly, so GBP and gbp do not mix £1.00, 1.00 gbp → error: currency mismatch
matching but invalid currencies are still refused 0.01 gbp, 0.01 gbp → error: ISO 4217

Files

PathBytes
README.md225
impl/python.py394
impl/rust.rs767
impl/typescript.ts432
vectors.json2,196