API Reference¶
All functions take an annual gross salary in GBP (£) as f64 and return
f64. None allocate. There are no external dependencies.
The crate exposes four functions and a set of public constants for the 2025/26
tax year. Import the crate as uk_paye (the underscore form, since crates.io
rejects hyphens in identifiers).
personal_allowance¶
The Personal Allowance for a given gross salary, after the £100k taper. Below £100,000 this is the full £12,570. Above £100,000 the allowance is reduced by £1 for every £2 of income over £100,000, reaching zero at £125,140. Floors at 0 — it never goes negative.
The taper is the well-known edge case a naive band calculator gets wrong: between £100k and £125,140 each extra £2 of salary both adds 40% higher-rate tax and pulls £1 of income out of the 0% band into the 40% band, producing a 60% effective marginal rate.
| Gross | Personal Allowance |
|---|---|
| £40,000 | £12,570.00 |
| £100,000 | £12,570.00 |
| £110,000 | £7,570.00 |
| £125,140 | £0.00 |
use uk_paye::personal_allowance;
assert!((personal_allowance(100_000.0) - 12_570.0).abs() < 1e-6);
assert!((personal_allowance(110_000.0) - 7_570.0).abs() < 1e-6);
assert!(personal_allowance(125_140.0).abs() < 1e-6);
income_tax¶
Annual UK income tax (excluding Scotland) for a gross salary. Applies the tapered Personal Allowance first, then the three marginal bands:
| Band | Rate | Taxable income (2025/26) |
|---|---|---|
| Basic rate | 20% | £12,571 – £50,270 |
| Higher rate | 40% | £50,271 – £125,140 |
| Additional rate | 45% | over £125,140 |
Because the allowance tapers above £100,000, income_tax is not piecewise
linear across the whole range — the taper is applied internally, so callers
never need to handle it separately.
use uk_paye::income_tax;
// £40,000: allowance £12,570 -> taxable £27,430 @ 20% = £5,486.00
assert!((income_tax(40_000.0) - 5_486.00).abs() < 1e-6);
// £50,000: taxable £37,430 @ 20% = £7,486.00
assert!((income_tax(50_000.0) - 7_486.00).abs() < 1e-6);
// £150,000: allowance tapered to £0; basic + higher + 45% on the excess
assert!((income_tax(150_000.0) - 54_331.50).abs() < 1e-6);
national_insurance¶
Class 1 employee National Insurance contributions for annual earnings. Employee NI does not use the tapered Personal Allowance — it has its own thresholds:
| Threshold | 2025/26 | Rate above it |
|---|---|---|
| Primary Threshold (PT) | £12,570 | 8% from PT up to the UEL |
| Upper Earnings Limit (UEL) | £50,270 | 2% on everything above |
So 8% applies to the slice between £12,570 and £50,270, and 2% to everything above £50,270. Earnings at or below £12,570 pay £0.
use uk_paye::national_insurance;
// £50,000 earnings: 8% on (50,000 - 12,570) = £2,994.40
assert!((national_insurance(50_000.0) - 2_994.40).abs() < 1e-6);
// £60,000: 8% on the UEL-PT band + 2% on the excess over £50,270
let expect = 0.08 * (50_270.0 - 12_570.0) + 0.02 * (60_000.0 - 50_270.0);
assert!((national_insurance(60_000.0) - expect).abs() < 1e-6); // £3,210.60
take_home¶
The headline function: net pay, income tax, and National Insurance as a tuple
(net, tax, ni). Equivalent to:
let t = income_tax(gross);
let n = national_insurance(gross);
let net = gross - t - n; // (net, t, n)
use uk_paye::take_home;
let (net, tax, ni) = take_home(50_000.0);
assert!((net - 39_519.60).abs() < 1e-6);
assert!((tax - 7_486.00).abs() < 1e-6);
assert!((ni - 2_994.40).abs() < 1e-6);
Constants¶
The 2025/26 thresholds are exposed as public constants for callers that need to reference or display the bands directly:
| Constant | Value | Meaning |
|---|---|---|
PERSONAL_ALLOWANCE |
12_570.0 |
0% band ceiling |
BASIC_LIMIT |
50_270.0 |
20% band ceiling |
HIGHER_LIMIT |
125_140.0 |
40% band ceiling / additional starts |
PA_TAPER_START |
100_000.0 |
Allowance begins tapering |
NI_PRIMARY_THRESHOLD |
12_570.0 |
Employee NI 8% starts |
NI_UPPER_LIMIT |
50_270.0 |
Employee NI drops to 2% |
NI_MAIN_RATE |
0.08 |
8% between PT and UEL |
NI_UPPER_RATE |
0.02 |
2% above UEL |
These are frozen for the 2025/26 tax year. If HMRC changes them, update the constants and every function follows.