This crate offers a two-byte serial number with wraparound.
A serial number is an identifier assigned incrementally to an item.
In many cases, you can use a u32
or u64
and call it
a day, without having to worry about overflow. The niche benefit of this type
is that it only uses the space of a u16
, with the problem of overflow solved
by wraparound.
[]
= "0.3"
# or with additional features:
[]
= { = "0.3", = ["serde"] }
The following feature flags implement additional traits for the Serial
type:
arbitrary
: derives arbitrary'sArbitrary
bincode
: derives bincode'sDecode/Encode
borsh
: derives borsh'sBorshDeserialize/BorshSerialize
rkyv
: derives rkyv'sArchive/Deserialize/Serialize
rkyv-safe
: additionally enables rkyv’s safe APIserde
: derives serde'sDeserialize/Serialize
The Minimum Supported Rust Version (MSRV) for this crate is 1.66.0
.
Usage
Simple example
use Serial;
// the default is a reference point - not serial number "zero"
let mut a = default;
let mut b = default;
let mut c = default;
// three ways to increase
let x = a.increase_get; // increase, then copy
let y = b.get_increase; // copy, then increase
c.increase;
assert!;
assert_eq!; // "diff()" is signed
assert_eq!; // "dist()" is unsigned
// addition is the same as calling "increase()" n times
assert_eq!;
Wraparound example
use Serial;
// a serial number can be increased indefinitely
let mut x = default;
for _ in 0..u16MAX
let x = x + u16MAX + u16MAX + u16MAX;
// comparison is trivial as long as two serial numbers have
// a distance of less than half of our number space (32767).
let a = default + 5;
let b = default + 32000;
assert!; // 5th successor < 32000th successor
// but: the comparison flips if the distance is larger
let a = default + 5;
let b = default + 65000;
assert!; // 5th successor > 65000th successor
// this means that you get the right ordering as long as
// you compare one serial number at most with one that
// is its 32767th successor.
// a real use case of this is to sign UDP packets with
// a serial number. this would allow you to restore the
// order of packets at the receiver as long as you never
// look at more than the 32767 last packets (which
// should be much more than you need).
The NAN
value
use Serial;
// "NAN" exists to have value representing "no serial number",
// since it saves encoding space vs wrapping Serial in an Option.
let nan = NAN;
let default = default;
// you can check whether a serial number is NAN
assert!;
// NAN cannot be increased
assert_eq!;
// distance between two NAN values is zero
assert_eq!;
assert_eq!;
// distance and difference of non-NAN to NAN is the maximum distance
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
// partial ordering does not include the NAN value
assert_eq!;
assert!;
Changelog
0.4.0 - 2023-05-05
- Set MSRV to
1.66.0
- Add some
#[must_use]
attributes
0.3.1 - 2023-04-28
- Add
documentation
toCargo.toml
- Fix outdated README
0.3.0 - 2023-04-28
- Set MSRV to
1.63.0
- Add
borsh
feature - Add
rkyv
andrkyv-safe
features - Add
arbitrary
feature
0.2.0 - 2023-04-27
- Set MSRV to
1.60.0
- Up
bincode
to^2.0.0-rc.3
- Improved documentation
0.1.1 - 2023-01-06
- Disabled the
std
features of bincode/serde to enableno_std
support.