Expand description
This crate provides an ergonomic, type-safe, and aesthetically-pleasing Size
type that can
be used to express, format, or operate on sizes. While it was initially created to make it
painless to “pretty print” file sizes (by automatically determining which unit and with what
precision a file size should be textually “written out” or formatted), it has expanded in scope
to make it easier and safer to perform the different types of operations that would arise when
dealing with sizes.
For almost all users, the only surface of interaction with this crate will take place via the
Size
type, which can be used to create a strongly-typed representation of a file size (or any
other “size” you need to deal with in the abstract). This crate’s API is intended to be as
natural and intuitive as possible, providing sensible defaults with zero boilerplate but also
allowing the developer to manually control aspects how sizes are expressed as text if needed.
The core Size
type is a simple wrapper around a signed numeric value - it can be initialized
using whatever primitive numeric type you wish, e.g. constructing a Size
from an i64
or from
a foo: f64
number of kilobytes.
§Using this crate and creating a Size
object
To use this crate, you only need to place use size::Size
at the top of your rust code, then
create a Size
from a constructor/initializer that matches the size you have on hand. Both
base-2 (KiB, MiB, etc) and base-10 (KB, MB, etc) units are supported and are exposed via the
same API. You can either use the abbreviated form of the unit to instantiate your type, or use
the full unit name to be more expressive. Here’s an example:
use size::Size;
// Create a strongly-typed size object. We don't even need to specify a numeric type!
let file1_size = Size::from_bytes(200);
// Create another Size instance, this time from a floating-point literal:
let file2_size = Size::from_kb(20.1);
You can obtain a scalar i64
value equal to the total number of bytes described by a
Size
instance by calling Size::bytes()
(see link for more info):
use size::Size;
let file_size = Size::from_gibibytes(4);
assert_eq!(file_size.bytes(), 4_294_967_296);
All Size
types can be directly compared (both for order and equality) to one another (or to
references of one another), regardless of their original type:
use size::Size;
let size1 = Size::from_kib(4 as u8);
let size2 = Size::from_bytes(4096 as i64);
assert_eq!(size1, size2);
let size1 = Size::from_kib(7);
let size2 = Size::from_kb(7);
assert!(&size2 < &size1);
§Textual representation
The majority of users will be interested in this crate for its ability to “pretty print” sizes
with little ceremony and great results. All Size
instances implement both
std::fmt::Display
and std::fmt::Debug
, so you can just directly format!(...)
or
println!(...)
with whatever Size
you have on hand:
use size::Size;
let file_size = Size::from_bytes(1_340_249);
let textual = format!("{}", file_size); // "1.28 MiB"
assert_eq!(textual.as_str(), "1.28 MiB");
Size::to_string()
can be used to directly return a String
containing
the formatted, human-readable size, instead of needing to use the format!()
macro or similar:
use size::Size;
let file_size = Size::from_bytes(1_340_249);
assert_eq!(file_size.to_string(), "1.28 MiB".to_string());
For fine-grained control over how a size is formatted and displayed, you can manually use the
Size::format()
function, which returns a FormattableSize
implementing the builder model to allow you to change one or more properties of how a Size
is formatted:
use size::{Size, Base, Style};
let file_size = Size::from_bytes(1_340_249); // same as before
let textual_size = file_size.format()
.with_base(Base::Base10)
.with_style(Style::FullLowercase)
.to_string();
assert_eq!(textual_size, "1.34 megabytes".to_string());
It is also possible to create and configure a standalone SizeFormatter
that can be reused to
format many sizes in a single, consistent style. This should not be seen as an alternative to
wrapping file sizes in strongly-typed Size
structs, which should always be the initial
instinct.
§Mathematical operations
You can perform mathematical operations on Size
types and the type safety makes sure that
what you’re doing makes sense:
use size::Size;
let sum = Size::from_mib(2) + Size::from_kib(200);
assert_eq!(sum, Size::from_mb(2.301_952));
let size = Size::from_gb(4.2) / 2;
assert_eq!(size, Size::from_gb(2.1));
See the documentation of the ops
module for more on this topic.
§Parsing sizes from text
The Size::from_str()
function can be used to convert the most commonly encountered textual
representations of file sizes into properly typed Size
objects, with flexible support for
various input whitespace formatting, abbreviated/full unit names, mixed upper/lower-case
representation, etc.
§Crate features
The following crate features may be chosen:
std
(enabled by default)serde
If compiled without the std
feature (i.e. with --no-default-features
or used as a dependency
with default features disabled), the crate becomes no_std
compatible. When used in no_std
mode, the following restrictions and limitations are observed:
- All formatting/stringification of
Size
types is disabled. Size
no longer implementsstd::fmt::Display
(core::fmt::Debug
is still implemented).- The intermediate type used for mathematical operations on
Size
types is changed fromf64
toi64
so that no implicit floating-point math is performed. To prevent inadvertent loss of precision, it is forbidden to pass in floating point values to theSize
API underno_std
mode. - The ability to parse strings into
Size
objects (Size::from_str()
and theFromStr
impl) are removed.
§Base-2 and Base-10 constants
You can individually use constants like size::KiB
or size::GB
directly or import all
constants into scope with use size::consts::*
(or just use size::*
, but that also imports
the types and traits defined by this crate, too).
§Serialization support
If the crate is compiled with the optional (default: disabled) serde
feature, the Size
type
may be serialized/deserialized directly to/from payloads via the serde
crate. The Size
type
is treated as a transparent new-type around u64
for serialization purposes (i.e. it serializes
directly to the number of bytes, not as a struct with the number of bytes as a member/field);
this allows deserializing payloads from various APIs or other languages that typically do not
use strongly-typed Size
objects to denote (file) size.
As an example, struct File { name: String, size: Size }
will serialize to { name: "name", size: 1234 }
instead of { name: "name", size: { bytes: 1234 }
.
Re-exports§
pub use crate::fmt::Base;
pub use crate::fmt::SizeFormatter;
pub use crate::fmt::Style;
pub use crate::consts::*;
Modules§
- consts
- A collection of constants for base-2 and base-10 units.
- fmt
- The
fmt
module containsSizeFormatter
and other types pertaining to formatting a size as human-readable text. - ops
- Implementations of basic arithmetic operations on/between
Size
values.
Structs§
- Parse
Size Error - Represents an error parsing a
Size
from a string representation. - Size
Size
is the core type exposed by this crate and allows the developer to express a file size (or the general concept of a “size”) as a strongly-typed, convertible type that can be used for textual formatting (“pretty printing”) and mathematical operations.