2026-11-06 14:56:13 +01:00
|
|
|
/**
|
|
|
|
|
* @fileoverview The formatters of the local model recommendation, and its byte units.
|
|
|
|
|
*
|
|
|
|
|
* `formatGb()` is the ONE place a byte count becomes a size a person reads: decimal GB (the
|
|
|
|
|
* unit the Finder and the model registry use). `hardware.ts` and `recommend.ts` call it to fill
|
|
|
|
|
* the `...Gb` text fields of the payload (`memGb`, `freeDiskGb`, `needGb`, `downloadGb`,
|
|
|
|
|
* `budgetGb`, and the size slots of a `LocalModelMessage`). Nothing else may turn bytes into a
|
|
|
|
|
* size for display, the browser included: it prints the text it was sent.
|
|
|
|
|
*
|
2026-11-06 22:16:37 +01:00
|
|
|
* GiB and MiB exist only for the budget math (reserves, the wired limit, the device total the
|
|
|
|
|
* runtime reports) and never reach a person, with one exception: `memClassGb()`, the memory
|
|
|
|
|
* size a Mac is sold as, is how the card names the installed memory ("48 GB memory", what
|
|
|
|
|
* About This Mac shows). It is a name of the machine, not a computed size: `formatGb()` of the
|
|
|
|
|
* same bytes reads 51.5, which no owner recognises. Every computed size (need, budget,
|
|
|
|
|
* download, free disk) is `formatGb()`.
|
2026-11-06 14:56:13 +01:00
|
|
|
*
|
|
|
|
|
* Pure: no IO, no state.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/** One decimal gigabyte, the unit a person reads. */
|
|
|
|
|
export const GB = 1_000_000_000;
|
|
|
|
|
/** One binary gigabyte. Budget math only. */
|
|
|
|
|
export const GIB = 1024 ** 3;
|
|
|
|
|
/** One binary megabyte. Budget math only. */
|
|
|
|
|
export const MIB = 1024 ** 2;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A byte count as decimal GB text, WITHOUT the unit: one decimal below 100 ('6.6', '17.7',
|
|
|
|
|
* '25.5'), a whole number from 100 ('212'). The caller's sentence supplies ' GB'.
|
|
|
|
|
* Anything that is not a positive finite number reads '0.0'.
|
|
|
|
|
*/
|
|
|
|
|
export function formatGb(bytes: number): string {
|
|
|
|
|
if (!Number.isFinite(bytes) || bytes <= 0) return '0.0';
|
|
|
|
|
const tenths = Math.round((bytes / GB) * 10) / 10;
|
|
|
|
|
return tenths >= 100 ? String(Math.round(bytes / GB)) : tenths.toFixed(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The memory size a Mac is sold as: whole binary gigabytes (17179869184 bytes is 16). This is
|
2026-11-06 17:37:53 +01:00
|
|
|
* `HardwareFacts.memClassGb`: the key of the tier rules ("below 36 GB") and of `TestedOn.memGb`,
|
|
|
|
|
* and what the card and the `noneMemory` sentence call the installed memory. It names a class
|
|
|
|
|
* of Mac; 0 means the size is unknown and is never shown. Any other size for display is
|
|
|
|
|
* `formatGb()`.
|
2026-11-06 14:56:13 +01:00
|
|
|
*/
|
|
|
|
|
export function memClassGb(memBytes: number): number {
|
|
|
|
|
if (!Number.isFinite(memBytes) || memBytes <= 0) return 0;
|
|
|
|
|
return Math.round(memBytes / GIB);
|
|
|
|
|
}
|