Skip to main content

human_units/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2#![doc = "# human-units\n\n[![Crates.io Version](https://img.shields.io/crates/v/human-units)](https://crates.io/crates/human-units)\n[![Docs](https://docs.rs/human-units/badge.svg)](https://docs.rs/human-units)\n[![dependency status](https://deps.rs/repo/github/igankevich/human-units/status.svg)](https://deps.rs/repo/github/igankevich/human-units)\n\nSize, duration and other SI units serialization and formatting library designed for configuration files and command line arguments.\n\n\n## Introduction\n\n`human-units` is a library with `Size`, `Duration` and other SI-related types specifically designed to be used in configuration files and as command line arguments.\nThese types serialize sizes and durations in _exact_ but human-readable form.\n\nThe library also provides `FormatSize`, `FormatDuration` traits\nto print _approximate_ values in a short human-readable form.\n\n- No floating point operations.\n- No dependencies by default.\n- Supports [serde](https://docs.rs/serde/latest/serde/).\n- Supports [clap](https://docs.rs/clap/latest/clap/).\n- Supports [`no_std`](https://docs.rust-embedded.org/book/intro/no-std.html).\n- Tested with [Miri](https://github.com/rust-lang/miri).\n- **72\u{2013}85%** faster than similar libraries (see benchmarks below).\n- **50\u{2013}87%** less binary size compared to similar libraries (see benchmarks below).\n\n\n## Examples\n\n### Exact human-readable size/duration\n\n```rust\nuse human_units::{Duration, Size};\nassert_eq!(\"1k\", Size(1024).to_string());\nassert_eq!(\"1025\", Size(1025).to_string());\nassert_eq!(\"1m\", Duration(core::time::Duration::from_secs(60)).to_string());\nassert_eq!(\"61s\", Duration(core::time::Duration::from_secs(61)).to_string());\n```\n\n### Inexact short human-readable size/duration\n\n```rust\nuse core::time::Duration;\nuse human_units::{FormatDuration, FormatSize};\nassert_eq!(\"1 KiB\", 1024_u64.format_size().to_string());\nassert_eq!(\"1 m\", Duration::from_secs(60).format_duration().to_string());\n```\n\n### Custom output\n\n```rust\nuse colored::Colorize;\nuse core::time::Duration;\nuse human_units::{FormatDuration, FormattedDuration};\n\n/// Prints the unit in cyan.\nstruct ColoredDuration(FormattedDuration);\n\nimpl core::fmt::Display for ColoredDuration {\n    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {\n        write!(f, \"{}\", self.0.integer)?;\n        if self.0.fraction != 0 {\n            write!(f, \".{}\", self.0.fraction)?;\n        }\n        write!(f, \" {}\", self.0.unit.cyan())\n    }\n}\n\n// prints \"1 m ago\", \"m\" is printed with cyan color\nprintln!(\"{} ago\", ColoredDuration(Duration::from_secs(60).format_duration()));\n```\n\n### Serde integration\n\n```rust\nuse human_units::Size;\nuse serde::Serialize;\n\n#[derive(Serialize, PartialEq, Eq, Debug)]\nstruct SizeWrapper {\n    size: Size,\n}\n\nlet object = SizeWrapper{ size: Size(1024) };\nassert_eq!(r#\"size = \"1k\"\"#, toml::to_string(&object).unwrap().trim());\n```\n\n### Clap integration\n\n```rust\nuse clap::Parser;\nuse human_units::{Duration, Size};\n\n#[derive(Parser, Debug)]\nstruct Args {\n    #[arg(long, value_parser=clap::value_parser!(Duration))]\n    timeout: Duration,\n    #[arg(long, value_parser=clap::value_parser!(Size))]\n    size: Size,\n}\n\nlet args = Args::parse_from([\"test-clap\", \"--timeout\", \"1m\", \"--size\", \"1g\"]);\nassert_eq!(args.timeout, Duration(core::time::Duration::from_secs(60)));\nassert_eq!(args.size, Size(1024_u64.pow(3)));\n```\n\n\n### SI units\n\n```rust\nuse human_units::si::{Frequency, Prefix};\n\n// Convert from hertz, internal representation is nHz (nanohertz).\nlet cpu_freq = Frequency::with_si_prefix(2200, Prefix::Mega);\nassert_eq!(\"2200 MHz\", cpu_freq.to_string());\nassert_eq!(\"2.2 GHz\", cpu_freq.format_si().to_string());\n```\n\n\n### IEC units\n\n```rust\nuse human_units::iec::{Byte, Prefix};\n\nlet size = Byte::with_iec_prefix(1536, Prefix::Kibi);\nassert_eq!(\"1536 KiB\", size.to_string());\nassert_eq!(\"1.5 MiB\", size.format_iec().to_string());\n```\n\n\n### Custom units\n\n```rust\nuse human_units::si::si_unit;\nuse human_units::iec::iec_unit;\n\n#[si_unit(symbol = \"l\")]\nstruct Volume(pub u64);\n\nlet volume = Volume(2_200_000_000);\nassert_eq!(\"2200 ml\", volume.to_string());\n\n#[iec_unit(symbol = \"B/s\")]\nstruct Throughput(pub u64);\n\nlet throughput = Throughput(100 * 1024);\nassert_eq!(\"100 KiB/s\", throughput.to_string());\n```\n\n## Performance benchmarks\n\nBenchmarks were done with Rust 1.80.1 on a x86\\_64 laptop.\n\n### Format size\n\n| Library | Version | Features | Benchmark | Time |\n|---------|---------|----------|-----------|------|\n| `human_bytes` | 0.4.3 | `fast`       | `format_size_then_to_string` | 88.40 ns \u{b1} 5.02 ns|\n| `human-repr`  | 1.1.0 | `1024,space` | `format_size_then_to_string` | 161.38 ns \u{b1} 13.29 ns|\n| `human-units` | 0.1.3 |              | `format_size_then_to_string` | **24.24 ns \u{b1} 1.23 ns** |\n\n### Format duration\n\n| Library | Version | Features | Benchmark | Time |\n|---------|---------|----------|-----------|------|\n| `human-repr`  | 1.1.0 | `1024,space` | `format_duration_then_to_string` | 229.47 ns \u{b1} 11.90 ns|\n| `human-units` | 0.1.3 |              | `format_duration_then_to_string` | **41.55 ns \u{b1} 2.77 ns** |\n\n\n## Executable size benchmarks\n\nBenchmarks were done with Rust 1.80.1 on a x86\\_64 laptop.\n\n### Format size\n\n| Library | Version | Features | Benchmark | Executable size, B |\n|---------|---------|----------|-----------|--------------------|\n| `human_bytes` | 0.4.3 | `fast`       | print formatted size | 8192  |\n| `human-repr`  | 1.1.0 | `1024,space` | print formatted size | 28672 |\n| `human-units` | 0.1.3 |              | print formatted size | 4096  |\n\n### Format duration\n\n| Library | Version | Features | Benchmark | Executable size, B |\n|---------|---------|----------|-----------|--------------------|\n| `human-repr`  | 1.1.0 | `1024,space` | print formatted duration | 28672 |\n| `human-units` | 0.1.3 |              | print formatted duration | 4096  |\n"include_str!("../README.md")]
3
4#[cfg(feature = "no_std")]
5compile_error!("Please use `cfg(not(feature = \"std\"))` instead of `cfg(feature = \"no_std\")`.");
6
7mod buffer;
8mod compat;
9mod duration;
10mod duration_format;
11#[cfg(feature = "serde")]
12mod duration_serde;
13mod error;
14pub mod iec;
15#[doc(hidden)]
16pub mod imp;
17pub mod si;
18mod size;
19mod size_format;
20#[cfg(feature = "serde")]
21mod size_serde;
22
23pub use self::buffer::*;
24pub(crate) use self::compat::*;
25pub use self::duration::*;
26pub use self::duration_format::*;
27pub use self::error::*;
28pub use self::size::*;
29pub use self::size_format::*;