A Rust crate for producing string representations of numbers, formatted according to international standards, e.g.
"1,000,000" for US English"10,00,000" for Indian English"1 000 000" for French Frenchnum-format offers three principal APIs...
ToFormattedStringThe [ToFormattedString] trait is the simplist of the three APIs. Just call
[to_formatted_string] on a type that implements it (all the integer types in the standard library
implement it) while providing a desired format (see picking a format below). That said, using
[ToFormattedString] will always heap allocate; so it is the slowest of the three APIs and cannot
be used in a no_std environment.
use num_format::{Locale, ToFormattedString};
fn main() {
let s = 1000000.to_formatted_string(&Locale::en);
assert_eq!(&s, "1,000,000");
}
BufferUsing the [Buffer] type is the fastest API, as it does not heap allocate. Instead, the
formatted representation is written into a stack-allocated buffer. As such, you can use it in a
no_std environment.
Although this API is available for all the integer types in the standard library, it is not
available for types like [num_bigint::BigInt] whose maximum size cannot be known in advance.
use num_format::{Buffer, Locale};
fn main() {
// Create a stack-allocated buffer...
let mut buf = Buffer::default();
// Write "1,000,000" into the buffer...
buf.write_formatted(&1000000, &Locale::en);
// Get a view into the buffer as a &str...
let s = buf.as_str();
// Do what you want with the &str...
assert_eq!("1,000,000", s);
}
WriteFormattedThe [WriteFormatted] trait is in between the other two APIs. You can write a formatted
representation into any type that implements [WriteFormatted] (all the types in the standard
library that implement [io::Write] or [fmt::Write] implement [WriteFormatted], such as
[Vec], [String], [File], etc.).
If you're writing a number type that can use the [Buffer] API, there is no heap allocation.
That said, the [io::Write] and [fmt::Write] machinery adds a bit of overhead; so it's faster
to use the [Buffer] type directly. This trait is not available in a no_std environment.
use num_format::{Locale, WriteFormatted};
fn main() {
// Create a writer...
let mut writer = String::new(); // Could also be Vec::new(), File::open(...), ...
// Write "1,000,000" into the writer...
writer.write_formatted(&1000000, &Locale::en);
assert_eq!(&writer, "1,000,000");
}
Formatting options (e.g. which thousands separator to use, what the minus sign looks like, etc.)
are represented by the [Format] trait. This crate offers three concrete implementations of
the [Format] trait...
LocaleThe [Locale] type is a programatically generated enum representing formatting standards from the
Common Locale Data Repository, which is maintained by the Unicode Consortium and used by
Apple in macOS and iOS, by LibreOffice, by IBM in AIX, among others.
use num_format::{Grouping, Locale};
fn main() {
let locale = Locale::en;
assert_eq!(locale.grouping(), Grouping::Standard);
assert_eq!(locale.minus_sign(), "-");
assert_eq!(locale.name(), "en");
assert_eq!(locale.separator(), ",");
let locale2 = Locale::from_name("en").unwrap();
assert_eq!(locale, locale2);
let available = Locale::available_names();
println!("All of the locale names available in the Unicode database are...");
println!("{:#?}", available);
}
SystemLocale (available behind feature flag with-system-locale)The SystemLocale type is another type that implements [Format]. It allows you to access your
OS's locale information. It has a very similar API to [Locale] and should work on all major
operating systems (i.e. macOS, linux, the BSDs, and Windows).
Since this type requires several dependencies (especially on Windows), it is behind a feature
flag. To use it, include num-format = { version = "0.4.3", features = ["with-system-locale"] }
in your Cargo.toml. Additionally, on Windows (but only on Windows), using SystemLocale
requires Clang 3.9 or higher.
use num_format::SystemLocale;
fn main() {
let locale = SystemLocale::default().unwrap();
println!("My system's default locale is...");
println!("{:#?}", &locale);
let available = SystemLocale::available_names().unwrap();
println!("My available locale names are...");
println!("{:#?}", available);
match SystemLocale::from_name("en_US") {
Ok(_) => println!("My system has the 'en_US' locale."),
Err(_) => println!("The 'en_US' locale is not included with my system."),
}
}
CustomFormat[CustomFormat] is the third and final type that implements [Format]. You can use it to build
your own custom formats.
use num_format::{Buffer, Error, CustomFormat, Grouping};
fn main() -> Result<(), Error> {
let format = CustomFormat::builder()
.grouping(Grouping::Indian)
.minus_sign("🙌")
.separator("😀")
.build()?;
let mut buf = Buffer::new();
buf.write_formatted(&(-1000000), &format);
assert_eq!("🙌10😀00😀000", buf.as_str());
Ok(())
}
--no-default-featureswith-system-locale feature and you're on Windows, Clang 3.9 or higher
is also required. See here for
installation instructions.| Available features | What to put in your Cargo.toml |
|---|---|
no_std |
num-format = { version = "0.4.3", default-features = false } |
with-num-bigint |
num-format = { version = "0.4.3", features = ["with-num-bigint"] } |
with-serde |
num-format = { version = "0.4.3", features = ["with-serde"] } |
with-system-locale |
num-format = { version = "0.4.3", features = ["with-system-locale"] } |
num-format is licensed under either of:
at your option.
$ claude mcp add num-format \
-- python -m otcore.mcp_server <graph>