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.
Crate features
This crate currently has one feature (std
), enabled by default. If compiled 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.
Re-exports
Modules
fmt
module contains SizeFormatter
and other types pertaining to formatting a size as
human-readable text.Size
values.Structs
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.