construction.brick-count
Bricks and mortar for a wall, openings subtracted, for UK standard 215 x 102.5 x 65 mm bricks with 10 mm joints.
1.0.0 · published 2026-10-03 by charlie · Anterra
Pinned by 17 tests, run in TypeScript, Python and Rust.
What it does
Bricks and mortar for a wall of UK standard bricks, with doors and windows subtracted.
## The brick
For example
brick_count(1, 1, , 1, 0%)→ net area square metres 1, bricks 60, mortar cubic metres 0.018 one square metre of half-brick wall is the trade's 60 bricksbrick_count(10, 2.4, openings ×2, 1, 5%)→ net area square metres 20.85, bricks 1,298, mortar cubic metres 0.387 a wall with a door and a window, 5 percent wastagebrick_count(1, 1, , 2, 0%)→ net area square metres 1, bricks 119, mortar cubic metres 0.046 a one-brick wall is 119 bricks a square metre, not 120, and adds a collar joint
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 brick_count(wall_length: f64, wall_height: f64, openings: &[Opening], skins: i64, wastage_basis_points: i64) -> BrickCount
| wall_length | float | metres, more than 0 and at most 1000; taken to the nearest millimetre |
| wall_height | float | metres, more than 0 and at most 100; taken to the nearest millimetre |
| openings | Opening[] | doors and windows to leave out; may be empty |
| skins | int | 1 for a half-brick wall, 2 for a one-brick wall; 1 to 4 |
| wastage_basis_points | int | cutting and breakage, applied to bricks and mortar, 500 = 5%; 0 to 10000 |
| returns | BrickCount |
The types it declares, generated into your project
/// A door, window or other hole in the wall, in metres.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Opening {
pub width: f64,
pub height: f64,
}
/// What to order for the wall.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct BrickCount {
/// the wall face less its openings
pub net_area_square_metres: f64,
/// including wastage, rounded up to whole bricks
pub bricks: i64,
/// including wastage, rounded up to the whole litre (3 dp)
pub mortar_cubic_metres: f64,
}
Your code names it in one line, in the file that uses it
fune!(construction.brick-count@^1); // then call brick_count(…)
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::math_round_div::round_div; ← from math.round-div ^1.0.0 · built alongside by fune
use super::math_round_float::round_float; ← from math.round-float ^1.0.0 · built alongside by fune
// A 215 x 65 mm brick face plus a 10 mm joint is 225 x 75 mm of wall.
const FACE_MM2: i64 = 225 * 75;
// Mortar per mm2 of wall face, in mm3: each skin fills the joints around a
// brick, (16875 - 215 x 65) / 16875 of the face, 102.5 mm deep, which is
// 2378/135 mm; each collar joint between skins is 10 mm = 1350/135 mm.
const SKIN_MORTAR: i64 = 2378;
const COLLAR_MORTAR: i64 = 1350;
const MORTAR_DIVISOR: i64 = 135;
const MM3_PER_LITRE: i64 = 1_000_000;
fn millimetres(value: f64, message: &str, max: i64) -> i64 {
if !value.is_finite() || value <= 0.0 || value > max as f64 {
panic!(
"{} must be a finite number greater than 0 and at most {} metres, received {}",
message, max, value
);
}
(round_float(value, 3) * 1000.0).round() as i64
}
/// Bricks and mortar for a wall of UK standard bricks, openings subtracted.
///
/// The count is the net face area over one brick's 225 x 75 mm share of it,
/// 59.26 per m2 per skin (the trade's "60 a metre"), times the skins, plus
/// wastage, rounded up. Mortar is the joint volume that geometry implies.
/// Everything is whole millimetres and integer arithmetic.
///
/// # Panics
/// Panics on a dimension, skin count or wastage out of range, or openings
/// larger than the wall.
pub fn brick_count(
wall_length: f64,
wall_height: f64,
openings: &[Opening],
skins: i64,
wastage_basis_points: i64,
) -> BrickCount {
let length = millimetres(wall_length, "wallLength", 1000);
let height = millimetres(wall_height, "wallHeight", 100);
if !(1..=4).contains(&skins) {
panic!("skins must be a whole number from 1 to 4, received {}", skins);
}
if !(0..=10000).contains(&wastage_basis_points) {
panic!("wastageBasisPoints must be a whole number from 0 to 10000, received {}", wastage_basis_points);
}
let mut net = length * height;
for (i, opening) in openings.iter().enumerate() {
let w = millimetres(opening.width, &format!("opening {}: width", i + 1), 1000);
let h = millimetres(opening.height, &format!("opening {}: height", i + 1), 1000);
net -= w * h;
}
if net < 0 {
panic!("openings are larger than the wall");
}
let bricks = round_div(net * skins * (10000 + wastage_basis_points), FACE_MM2 * 10000, "up");
let per_mm2 = skins * SKIN_MORTAR + (skins - 1) * COLLAR_MORTAR;
// Up to the whole litre first, then the wastage, so no product passes 2^53.
let litres = round_div(net * per_mm2, MORTAR_DIVISOR * MM3_PER_LITRE, "up");
let mortar = round_div(litres * (10000 + wastage_basis_points), 10000, "up");
BrickCount {
net_area_square_metres: net as f64 / 1_000_000.0,
bricks,
mortar_cubic_metres: mortar as f64 / 1000.0,
}
}
pub fn brick_count_to_value(b: &BrickCount) -> Value {
Value::obj(vec![
("netAreaSquareMetres", Value::Float(b.net_area_square_metres)),
("bricks", Value::Int(b.bricks)),
("mortarCubicMetres", Value::Float(b.mortar_cubic_metres)),
])
}
pub fn fune_vector(args: &[Value]) -> Value {
let openings: Vec<Opening> = args[2]
.as_arr()
.iter()
.map(|v| Opening { width: v.get("width").as_f64(), height: v.get("height").as_f64() })
.collect();
if let Value::Float(f) = &args[3] {
panic!("skins must be a whole number from 1 to 4, received {}", f);
}
if let Value::Float(f) = &args[4] {
panic!("wastageBasisPoints must be a whole number from 0 to 10000, received {}", f);
}
brick_count_to_value(&brick_count(
args[0].as_f64(),
args[1].as_f64(),
&openings,
args[3].as_i64(),
args[4].as_i64(),
))
}Install
fune build
With that line in your source, in a Rust project (language rust in fune.project), fune build resolves it and its 2 dependencies, 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 construction.brick-count
The manifest, vectors and README with only the Rust implementation. Install it without the registry with fune add ./construction.brick-count-1.0.0-rust.fune, or fetch it from a terminal with fune pull construction.brick-count@1.0.0:rust.
The whole function, every language, is one file too: construction.brick-count-1.0.0.fune, 19,874 bytes, sha256 4c520d53927a6f63aa67ea0907846e0323782667d63ef704067c362ffc799a8f. 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 construction.brick-count
after — your function gets the result and the arguments, and returns the final result.
// fune: after construction.brick-count
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 math.round-div in construction.brick-count
// fune: replace math.round-float in construction.brick-count
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 construction.brick-count --steps.
// fune: step construction.brick-count 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.
| Case | Arguments | Expected | |
|---|---|---|---|
| one square metre of half-brick wall is the trade's 60 bricks | 1, 1, , 1, 0% | → | net area square metres 1, bricks 60, mortar cubic metres 0.018 |
| a wall with a door and a window, 5 percent wastage | 10, 2.4, openings ×2, 1, 5% | → | net area square metres 20.85, bricks 1,298, mortar cubic metres 0.387 |
| a one-brick wall is 119 bricks a square metre, not 120, and adds a collar joint | 1, 1, , 2, 0% | → | net area square metres 1, bricks 119, mortar cubic metres 0.046 |
| exactly 100 bricks plus 10 percent is exactly 110 | 2.25, 0.75, , 1, 10% | → | net area square metres 1.688, bricks 110, mortar cubic metres 0.033 |
| a garden wall that comes out to exactly 336 bricks with wastage | 6, 0.9, , 1, 5% | → | net area square metres 5.4, bricks 336, mortar cubic metres 0.101 |
| three skins | 1, 1, , 3, 0% | → | net area square metres 1, bricks 178, mortar cubic metres 0.073 |
| dimensions are taken to the nearest millimetre | 3, 1, , 1, 0% | → | net area square metres 3, bricks 178, mortar cubic metres 0.053 |
| an opening the size of the wall leaves nothing to build | 2, 1, openings ×1, 1, 5% | → | net area square metres 0, bricks 0, mortar cubic metres 0 |
| openings larger than the wall are an error | 2, 1, openings ×1, 1, 0% | → | error: openings are larger than the wall |
| no skins is an error | 1, 1, , 0, 0% | → | error: skins must be a whole number from 1 to 4 |
Show the other 7 tests
| Case | Arguments | Expected | |
|---|---|---|---|
| five skins is an error | 1, 1, , 5, 0% | → | error: skins must be a whole number from 1 to 4 |
| a fractional skin count is an error | 1, 1, , 1.5, 0% | → | error: skins must be a whole number from 1 to 4 |
| a zero-length wall is an error | 0, 1, , 1, 0% | → | error: wallLength must be a finite number greater than 0 and at most 1000 metres |
| a wall over 100 metres high is an error | 5, 101, , 1, 0% | → | error: wallHeight must be a finite number greater than 0 and at most 100 metres |
| a negative opening is an error | 5, 2, openings ×1, 1, 0% | → | error: opening 1: width must be a finite number greater than 0 and at most 1000 metres |
| negative wastage is an error | 1, 1, , 1, -0.01% | → | error: wastageBasisPoints must be a whole number from 0 to 10000 |
| fractional wastage is an error | 1, 1, , 1, 0.025% | → | error: wastageBasisPoints must be a whole number from 0 to 10000 |
More from the author
A UK metric brick is 215 × 102.5 × 65 mm (work size). Laid with 10 mm joints it occupies 225 × 75 mm of wall face (the coordinating size), so one square metre of a half-brick (single-skin) wall takes 1,000,000 / 16,875 = 59.26 bricks, which the trade calls "60 a metre". A one-brick wall (two skins) is twice that, 118.5, so 119 for a square metre rather than the 120 that doubling the rounded figure gives.
## How it is worked out
1. Wall and openings, given in metres, are taken to the nearest millimetre; the net face area is the wall less the openings, in whole mm². 2. **Bricks** = net area × skins × (1 + wastage) ÷ 16,875 mm², rounded up. 3. **Mortar** is the joint volume the geometry implies, not a rule of thumb: per skin, the joints are (16,875 − 215 × 65) / 16,875 of the face, 102.5 mm deep, which is 17.6 litres per m²; each collar joint between skins adds a 10 mm layer, 10 litres per m². Rounded up to a whole litre, then the wastage added and rounded up to a litre again.
All arithmetic is in integers after step 1, so it does not suffer from floating-point ceilings.
## What it does not count
Frogs and perforations (a frog-up brick takes more mortar; add it to the wastage), cavity walls built with a block inner leaf (count the brick skin here, blocks separately), ties, lintels, piers and returns, and the bond: English and Flemish bond one-brick walls use the same number of bricks per m² as two stretcher skins, but headers change how many facing bricks you need.
Limits: length up to 1000 m, height up to 100 m, 1 to 4 skins, wastage 0 to 10,000 basis points. Openings larger than the wall are an error; openings equal to it leave nothing to build.
## Sources
- BS EN 771-1 (clay masonry units) and the UK standard format of 215 × 102.5 × 65 mm with a 225 × 112.5 × 75 mm coordinating size; see "Brick sizes", Designing Buildings Wiki, https://www.designingbuildings.co.uk/wiki/Brick_sizes - The 60 bricks per m² single-skin rule as used in the UK trade, e.g. https://www.imperialbricks.co.uk/guidance/bricks-per-m2-guide/
Files
| Path | Bytes |
|---|---|
| README.md | 2,227 |
| impl/python.py | 3,006 |
| impl/rust.rs | 3,842 |
| impl/typescript.ts | 2,842 |
| vectors.json | 4,191 |