mf2_runtime/host.rs
1//! What the runtime asks of its platform:
2//! the shortest text of a float (no float-printing code in the
3//! wasm), for dates the UTC offset of a named time zone and —
4//! with the `intl` date formatter — a date formatter, and — `intl` — a number formatter
5//! with plural rules. `mf2-host-std` implements it natively and for
6//! `wasm32-wasip1`, `mf2-host-web` in the browser.
7//!
8//! Canonical equivalence is not among them: the runtime answers it itself,
9//! from the map its catalog carries (`crate::nfc_equivalent`, `plan/01`
10//! §4.3), so no host needs normalization tables.
11
12use crate::datetime::DateTimeRequest;
13use crate::number::{NumberOut, NumberRequest};
14use crate::plural::Category;
15use crate::sink::Sink;
16
17/// The platform services the runtime needs.
18pub trait Host: Sync {
19 /// The shortest decimal text that round-trips the finite `x`, written
20 /// into `buf`: any form `number-literal` accepts, with an optional `+` in
21 /// the exponent (`ryu`'s `4.2`, `1e21`, `1.5e-7` and JavaScript's
22 /// `String(x)` both qualify). `None` if the host cannot produce it.
23 fn f64_to_text<'b>(&self, x: f64, buf: &'b mut [u8; 32]) -> Option<&'b str>;
24
25 /// The UTC offset, in seconds east, of the IANA time zone `zone` at the
26 /// instant `epoch_ms` (milliseconds since the epoch). `None`: the host
27 /// has no zone data, or knows no such zone (the default) — a date/time
28 /// function that must convert an instant to a named zone then reports
29 /// *Bad Option* and a fallback value (datetime.md allows it; a wall time
30 /// in the wrong zone would be worse).
31 fn zone_offset(&self, zone: &str, epoch_ms: i64) -> Option<i32> {
32 let _ = (zone, epoch_ms);
33 None
34 }
35
36 /// The `intl` date formatter: writes `request` formatted by the host's date
37 /// formatter (the browser's `Intl.DateTimeFormat`) for `locale`, and
38 /// returns `true`; `false` (the default) when the host has none.
39 fn format_date_time(
40 &self,
41 locale: &str,
42 request: &DateTimeRequest<'_>,
43 out: &mut dyn Sink,
44 ) -> bool {
45 let _ = (locale, request, out);
46 false
47 }
48
49 /// `intl`: the host's number formatter (in the browser `Intl.NumberFormat`
50 /// and `Intl.PluralRules`, when the engine has `Intl.NumberFormat` v3);
51 /// `None` (the default) when it has none — the numeric functions of an
52 /// `intl` client then show exact digits and report *Unsupported
53 /// Operation*.
54 fn numbers(&self) -> Option<&dyn NumberFormatter> {
55 None
56 }
57}
58
59/// A number formatter for the `intl` option ([`Host::numbers`]):
60/// the final "value + resolved options →
61/// text" step and the plural category, where the numeric functions keep
62/// MF2's semantics in Rust. `mf2-host-web` implements it with `Intl`.
63pub trait NumberFormatter: Sync {
64 /// Writes `request` formatted for `locale` — or, when `request.neutral`,
65 /// in neutral symbols — as text or sub-parts, and returns `true`;
66 /// `false` when it cannot (nothing written).
67 fn format(&self, locale: &str, request: &NumberRequest<'_>, out: NumberOut<'_>) -> bool;
68
69 /// The plural category of `request.value` under its digit options and
70 /// plural type (`request.ordinal`) for `locale`; `None` when it cannot.
71 fn plural(&self, locale: &str, request: &NumberRequest<'_>) -> Option<Category>;
72}