mf2_runtime/lib.rs
1//! `mf2-runtime` — the MessageFormat 2 evaluator of Rust MF2: it formats a message **from a catalog**, walking
2//! `mf2-catalog`'s views in place — resolution, declarations (lazily, each at
3//! most once), selection, fallback, the Default Bidi Strategy, format to
4//! parts, markup, the `u:` options — and it holds the function registry, the
5//! custom-function API and the core functions: `:string`, and `:number`,
6//! `:integer`, `:offset` with their complete semantics and neutral symbols.
7//!
8//! | Item | What |
9//! |---|---|
10//! | [`Formatter`] | the entry point: `simple`, `write`, `parts`, `*_named` |
11//! | [`Sink`], [`PartSink`], [`ErrorSink`] | where output and errors go |
12//! | [`Arg`], [`Value`], [`Number`] | arguments and resolved values |
13//! | [`Function`], [`Registry`], [`functions`] | handlers; a registry names only the handlers its corpus uses, and no other is linked |
14//! | [`Host`] | NFC, float text, zone offsets, a date formatter, a number formatter (`intl`) from the platform |
15//! | [`DateTime`], [`TimeZone`], [`NumberSpec`], [`Digits`], [`Measure`] | what the function crates and custom functions build on |
16//!
17//! Client-path code: `no_std` + `alloc`, `forbid(unsafe_code)`, no
18//! `core::fmt`, no panicking operation; built-in handlers never allocate.
19//!
20//! # The user guide
21//!
22//! The [Rust MF2 book](https://evancarroll.github.io/rust-mf2/) is the user
23//! guide: how the crates fit together, web and native applications, the
24//! command line, and what 2.x promises.
25//! An application reaches this crate through
26//! [`mf2`](https://docs.rs/mf2), which re-exports it; a custom function is
27//! written against [`Function`].
28
29#![warn(missing_docs, missing_debug_implementations)]
30// docs.rs (`cargo xtask docs-rs`): each feature-gated item says which features it needs.
31#![cfg_attr(docsrs, feature(doc_cfg))]
32#![no_std]
33#![forbid(unsafe_code)]
34#![deny(
35 clippy::unwrap_used,
36 clippy::expect_used,
37 clippy::indexing_slicing,
38 clippy::panic
39)]
40
41extern crate alloc;
42
43mod datetime;
44mod error;
45mod eval;
46mod format;
47mod function;
48pub mod functions;
49mod host;
50mod nfc;
51mod number;
52mod parts;
53mod plural;
54mod scratch;
55mod sink;
56mod text;
57mod unannotated;
58mod value;
59
60#[doc(hidden)]
61pub use mf2_catalog::StrRef;
62pub use mf2_catalog::{Catalog, Dir, MsgId};
63pub use mf2_model::MarkupKind;
64
65pub use datetime::{
66 Date, DateFields, DateLength, DateStyle, DateTime, DateTimeOptions, DateTimeRequest, Time,
67 TimePrecision, TimeZone, ZoneOption, ZoneStyle, is_zone_name,
68};
69pub use error::FormatError;
70pub use format::{BidiStrategy, FormatContext, Formatter};
71pub use function::{FnContext, Function, OptionValue, Options, Registry};
72pub use host::{Host, NumberFormatter};
73/// Canonical equivalence with a catalog key from the catalog's map, for the
74/// differential fuzz target (`fuzz/fuzz_targets/nfc.rs`) and the
75/// conformance crate's differential test, both of which check it against
76/// full NFC. Applications use [`FnContext::equivalent`].
77#[doc(hidden)]
78pub use nfc::equivalent as nfc_equivalent;
79pub use number::{
80 CurrencyDisplay, DigitOptions, Digits, Grouping, Measure, MeasureUnit, Number, NumberOut,
81 NumberRequest, NumberSpec, NumberStyle, RoundingMode, RoundingPriority, Sign, SignDisplay,
82 UnitDisplay,
83};
84pub use parts::{
85 ExpressionPart, FallbackSource, Isolation, MarkupOptions, MarkupPart, Part, PartSink,
86};
87#[doc(hidden)]
88pub use plural::select as plural_category;
89pub use plural::{Category, Operands};
90pub use sink::{ErrorSink, NoErrors, Sink, SubPartSink};
91pub use value::{Arg, CustomValue, Value};
92
93/// Whether numbers format through the host:
94/// feature `web-number-intl` without `web-number-builtin`, on
95/// `wasm32-unknown-unknown` only. The numeric
96/// functions — the core's and `mf2-fn-number`'s — then take the display,
97/// `:integer`'s rounding and the plural category from
98/// the host's [`NumberFormatter`] ([`Host::numbers`]: the browser's
99/// `Intl.NumberFormat` and `Intl.PluralRules`) instead of the Rust digit
100/// plan, rounding and plural evaluator, which are not linked. Everywhere
101/// else — servers, `wasm32-wasip1`, native tests, and a browser with
102/// `web-number-builtin` — `false`: the Rust path.
103#[doc(hidden)]
104pub const INTL_NUMBERS: bool = cfg!(all(
105 feature = "web-number-intl",
106 not(feature = "web-number-builtin"),
107 target_arch = "wasm32",
108 target_os = "unknown"
109));
110// The backend the numeric functions were compiled over is the one the
111// constant states: the two are chosen by the same condition, written twice.
112const _: () = assert!(INTL_NUMBERS == number::BY_HOST);
113// With both of a browser's number features on, this crate's own code
114// formats: the stronger of the two, whichever crate asked for the other.
115#[cfg(feature = "web-number-builtin")]
116const _: () = assert!(!INTL_NUMBERS);