rusty_ulid 2.0.0

Rust ULID (Universally Unique Lexicographically Sortable Identifier) generation and processing
Documentation
/*
 * The MIT License (MIT)
 * Copyright (c) 2018-2023 Joern Huxhorn
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the “Software”), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/*
 * Copyright 2018-2023 Joern Huxhorn
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#![doc(html_root_url = "https://docs.rs/rusty_ulid/2.0.0")]
#![deny(
    anonymous_parameters,
    bare_trait_objects,
    missing_copy_implementations,
    missing_debug_implementations,
    missing_docs,
    rust_2018_idioms,
    trivial_casts,
    trivial_numeric_casts,
    unreachable_pub,
    unused_import_braces,
    unused_qualifications,
    unused_results,
    variant_size_differences
)]
#![warn(clippy::all)]
//#![deny(clippy::pedantic)]
#![forbid(unsafe_code)]
#![allow(unknown_lints)]

//! # ULID - Universally Unique Lexicographically Sortable Identifier
//!
//! UUID can be suboptimal for many uses-cases because:
//!
//! - It isn't the most character efficient way of encoding 128 bits of randomness
//! - UUID v1/v2 is impractical in many environments, as it requires access to a unique, stable MAC address
//! - UUID v3/v5 requires a unique seed and produces randomly distributed IDs, which can cause fragmentation in many data structures
//! - UUID v4 provides no other information than randomness which can cause fragmentation in many data structures
//!
//! Instead, herein is proposed [ULID][ulidspec]:
//!
//! `01ARZ3NDEKTSV4RRFFQ69G5FAV`
//!
//! - 128-bit compatibility with UUID
//! - 1.21e+24 unique ULIDs per millisecond
//! - Lexicographically sortable!
//! - Canonically encoded as a 26 character string, as opposed to the 36 character UUID
//! - Uses [Crockford's base32][crockford] for better efficiency and readability (5 bits per character)
//! - Case insensitive
//! - No special characters (URL safe)
//! - Monotonic sort order (correctly detects and handles the same millisecond)
//!
//! ## Specification
//!
//! Below is the current specification of [ULID][ulidspec] as implemented in this crate.
//!
//!
//! ```text
//!  01AN4Z07BY      79KA1307SR9X4MV3
//!
//! |----------|    |----------------|
//!  Timestamp          Randomness
//!    48bits             80bits
//! ```
//!
//! ### Components
//!
//! #### Timestamp
//! - 48 bit integer
//! - UNIX-time in milliseconds
//! - Won't run out of space until `+10889-08-02T05:31:50.655Z`.
//!
//! #### Randomness
//! - 80 bits
//! - Cryptographically secure source of randomness, if possible
//!
//! ### Sorting
//!
//! The left-most character must be sorted first, and the right-most character
//! sorted last (lexical order). The default ASCII character set must be used.
//! Within the same millisecond, sort order is not guaranteed
//!
//! ### Canonical String Representation
//!
//! ```text
//! ttttttttttrrrrrrrrrrrrrrrr
//!
//! where
//! t is Timestamp (10 characters)
//! r is Randomness (16 characters)
//! ```
//!
//! ### Encoding
//!
//! [Crockford's Base32][crockford] is used as shown.
//! This alphabet excludes the letters I, L, O, and U to avoid confusion and abuse.
//!
//! `0123456789ABCDEFGHJKMNPQRSTVWXYZ`
//!
//! ### Monotonicity
//!
//! When generating a ULID within the same millisecond, we can provide some
//! guarantees regarding sort order. Namely, if the same millisecond is detected,
//! the `random` component is incremented by 1 bit in the least significant bit position
//! (with carrying).
//!
//! If, in the extremely unlikely event that, you manage to generate more than 2<sup>80</sup>
//! ULIDs within the same millisecond, or cause the random component to overflow with less,
//! the generation will fail.
//!
//! ### Overflow Errors when Parsing Base32 Strings
//!
//! Technically, a 26-character Base32 encoded string can contain 130 bits of
//! information, whereas a ULID must only contain 128 bits. Therefore, the largest
//! valid ULID encoded in Base32 is `7ZZZZZZZZZZZZZZZZZZZZZZZZZ`, which corresponds to
//! an epoch time of `281474976710655` or `2 ^ 48 - 1`.
//!
//! Any attempt to decode or encode a ULID larger than this should be rejected by all
//! implementations, to prevent overflow bugs.
//!
//! ### Binary Layout and Byte Order
//!
//! The components are encoded as 16 octets. Each component is encoded with the
//! Most Significant Byte first (network byte order).
//!
//! ```text
//! 0                   1                   2                   3
//!  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//! |                      32_bit_uint_time_high                    |
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//! |     16_bit_uint_time_low      |       16_bit_uint_random      |
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//! |                       32_bit_uint_random                      |
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//! |                       32_bit_uint_random                      |
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//! ```
//!
//! [ulidspec]: https://github.com/ulid/spec
//! [crockford]: https://crockford.com/wrmg/base32.html

#[cfg(feature = "time")]
use time::OffsetDateTime;

#[cfg(feature = "chrono")]
use chrono::prelude::{DateTime, TimeZone, Utc};

use std::convert::TryFrom;
use std::fmt;
use std::str::FromStr;

#[cfg(feature = "serde")]
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
#[cfg(feature = "rocket")]
mod rocket_;
#[cfg(feature = "schemars")]
mod schemars;

/// Contains functions for encoding and decoding of
/// [crockford Base32][crockford] strings.
///
/// [crockford]: https://crockford.com/wrmg/base32.html
pub mod crockford;
pub use crate::crockford::DecodingError;

/// Returns the number of non-leap milliseconds since 1970-01-01T00:00:00Z
/// (aka "UNIX timestamp").
#[cfg(all(feature = "rand", any(feature = "chrono", feature = "time")))]
fn unix_epoch_ms() -> u64 {
    #[cfg(feature = "time")]
    {
        let now = OffsetDateTime::now_utc();

        now.unix_timestamp() as u64 * 1_000 + now.millisecond() as u64
    }
    #[cfg(all(feature = "chrono", not(feature = "time")))]
    {
        let now: DateTime<Utc> = Utc::now();

        now.timestamp_millis() as u64
    }
}

/// Returns a new ULID string.
///
/// This function is a shortcut for `Ulid::generate().to_string()`.
///
/// # Example
/// ```
/// # use rusty_ulid::generate_ulid_string;
/// let ulid_string = generate_ulid_string();
///
/// // every ulid has exactly 26 characters
/// assert_eq!(ulid_string.len(), 26);
/// ```
#[cfg(all(feature = "rand", any(feature = "chrono", feature = "time")))]
#[must_use]
pub fn generate_ulid_string() -> String {
    Ulid::generate().to_string()
}

/// Returns new ULID bytes.
///
/// This function is a shortcut for `Ulid::generate().into()`.
///
/// # Example
/// ```
/// # use rusty_ulid::generate_ulid_bytes;
/// let ulid_bytes = generate_ulid_bytes();
///
/// // a binary ulid has exactly 16 bytes
/// assert_eq!(ulid_bytes.len(), 16);
/// ```
#[cfg(all(feature = "rand", any(feature = "chrono", feature = "time")))]
#[must_use]
pub fn generate_ulid_bytes() -> [u8; 16] {
    Ulid::generate().into()
}

#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)]
/// The ULID data type.
pub struct Ulid {
    value: (u64, u64),
}

impl Ulid {
    /// Creates a new ULID.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let ulid = Ulid::generate();
    ///
    /// assert_ne!(0, ulid.timestamp());
    ///
    /// let ulid_string = ulid.to_string();
    /// // every ulid has exactly 26 characters
    /// assert_eq!(ulid_string.len(), 26);
    /// ```
    ///
    /// # Panics
    ///
    /// Panics if called after `+10889-08-02T05:31:50.655Z`.
    #[cfg(all(feature = "rand", any(feature = "chrono", feature = "time")))]
    #[must_use]
    pub fn generate() -> Self {
        Self::from_timestamp_with_rng(unix_epoch_ms(), &mut rand::thread_rng())
    }

    /// Creates the next monotonic ULID for the given `previous_ulid`.
    ///
    /// If the random part of `previous_ulid` would overflow, this function returns a ULID with
    /// the random part set to zero.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let previous_ulid = Ulid::from(0);
    /// let ulid = Ulid::next_monotonic(previous_ulid);
    ///
    /// assert_ne!(0, ulid.timestamp());
    /// ```
    ///
    /// # Panics
    ///
    /// Panics if called after `+10889-08-02T05:31:50.655Z`.
    #[cfg(all(feature = "rand", any(feature = "chrono", feature = "time")))]
    #[must_use]
    pub fn next_monotonic(previous_ulid: Self) -> Self {
        Self::next_monotonic_from_timestamp_with_rng(
            previous_ulid,
            unix_epoch_ms(),
            &mut rand::thread_rng(),
        )
    }

    /// Creates the next strictly monotonic ULID for the given `previous_ulid`.
    ///
    /// If the random part of `previous_ulid` would overflow, this function returns `None`.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let previous_ulid = Ulid::from(0);
    /// let ulid = Ulid::next_strictly_monotonic(previous_ulid);
    ///
    /// if let Some(ulid) = ulid {
    ///     assert_ne!(0, ulid.timestamp());
    /// }
    /// ```
    ///
    /// # Panics
    ///
    /// Panics if called after `+10889-08-02T05:31:50.655Z`.
    #[cfg(all(feature = "rand", any(feature = "chrono", feature = "time")))]
    #[must_use]
    pub fn next_strictly_monotonic(previous_ulid: Self) -> Option<Self> {
        Self::next_strictly_monotonic_from_timestamp_with_rng(
            previous_ulid,
            unix_epoch_ms(),
            &mut rand::thread_rng(),
        )
    }

    /// Creates a new ULID with the given `timestamp` obtaining randomness from
    /// `rng`.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let ulid = Ulid::from_timestamp_with_rng(0, &mut rand::thread_rng());
    ///
    /// let timestamp = ulid.timestamp();
    ///
    /// assert_eq!(timestamp, 0);
    /// ```
    ///
    /// # Panics
    ///
    /// Panics if `timestamp` is larger than `0xFFFF_FFFF_FFFF`.
    #[cfg(feature = "rand")]
    pub fn from_timestamp_with_rng<R>(timestamp: u64, rng: &mut R) -> Self
    where
        R: rand::Rng,
    {
        if (timestamp & 0xFFFF_0000_0000_0000) != 0 {
            panic!("ULID does not support timestamps after +10889-08-02T05:31:50.655Z");
        }

        let high = timestamp << 16 | u64::from(rng.gen::<u16>());
        let low = rng.gen::<u64>();
        let value = (high, low);

        Self { value }
    }

    /// Creates the next monotonic ULID with the given `previous_ulid`, `timestamp`
    /// obtaining randomness from `rng`.
    ///
    /// If the random part of `previous_ulid` would overflow, this function returns a ULID with
    /// the random part set to zero.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let previous_ulid = Ulid::from(0);
    /// let ulid = Ulid::next_monotonic_from_timestamp_with_rng(previous_ulid, 0, &mut rand::thread_rng());
    ///
    /// assert_eq!(ulid, Ulid::from(1));
    /// ```
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let previous_ulid = Ulid::from(0x0000_0000_0000_FFFF_FFFF_FFFF_FFFF_FFFE);
    /// let ulid = Ulid::next_monotonic_from_timestamp_with_rng(previous_ulid, 0, &mut rand::thread_rng());
    ///
    /// assert_eq!(ulid, Ulid::from(0x0000_0000_0000_FFFF_FFFF_FFFF_FFFF_FFFF));
    /// ```
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let previous_ulid = Ulid::from(0x0000_0000_0000_FFFF_FFFF_FFFF_FFFF_FFFF);
    /// let ulid = Ulid::next_monotonic_from_timestamp_with_rng(previous_ulid, 0, &mut rand::thread_rng());
    ///
    /// // overflow results in zero random part
    /// assert_eq!(ulid, Ulid::from(0));
    /// ```
    ///
    /// # Panics
    ///
    /// Panics if `timestamp` is larger than `0xFFFF_FFFF_FFFF`.
    #[cfg(feature = "rand")]
    pub fn next_monotonic_from_timestamp_with_rng<R>(
        previous_ulid: Self,
        timestamp: u64,
        rng: &mut R,
    ) -> Self
    where
        R: rand::Rng,
    {
        Self::next_monotonic_from_timestamp_with_rng_and_postprocessor(
            Some(previous_ulid),
            timestamp,
            rng,
            None,
        )
    }

    /// Creates the next monotonic ULID with the given `previous_ulid`, `timestamp`
    /// obtaining randomness from `rng`. If a new ULID is created instead of simply
    /// incrementing the previous ULID, then `postprocessor` is used (if available)
    /// to transform the new ULID before returning it.
    ///
    /// If the random part of `previous_ulid` would overflow, this function returns a ULID with
    /// the random part set to zero.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let previous_ulid = Ulid::from(0);
    /// let ulid = Ulid::next_monotonic_from_timestamp_with_rng_and_postprocessor(Some(previous_ulid), 0, &mut rand::thread_rng(), None);
    ///
    /// assert_eq!(ulid, Ulid::from(1));
    /// ```
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let previous_ulid = Ulid::from(0x0000_0000_0000_FFFF_FFFF_FFFF_FFFF_FFFE);
    /// let ulid = Ulid::next_monotonic_from_timestamp_with_rng_and_postprocessor(Some(previous_ulid), 0, &mut rand::thread_rng(), None);
    ///
    /// assert_eq!(ulid, Ulid::from(0x0000_0000_0000_FFFF_FFFF_FFFF_FFFF_FFFF));
    /// ```
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let previous_ulid = Ulid::from(0x0000_0000_0000_FFFF_FFFF_FFFF_FFFF_FFFF);
    /// let ulid = Ulid::next_monotonic_from_timestamp_with_rng_and_postprocessor(Some(previous_ulid), 0, &mut rand::thread_rng(), None);
    ///
    /// // overflow results in zero random part
    /// assert_eq!(ulid, Ulid::from(0));
    /// ```
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// fn postprocessor_fn(ulid: Ulid) -> Ulid {
    ///     // zero out lowest 32 bits
    ///     Ulid::from(u128::from(ulid) & 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_0000_0000)
    /// }
    ///
    /// let previous_ulid = Ulid::from(0);
    /// let ulid = Ulid::next_monotonic_from_timestamp_with_rng_and_postprocessor(
    ///     Some(previous_ulid),
    ///     1,
    ///     &mut rand::thread_rng(),
    ///     Some(&postprocessor_fn),
    /// );
    ///
    /// assert_eq!(0, u128::from(ulid) & 0xFFFF_FFFF);
    ///
    /// let ulid = Ulid::next_monotonic_from_timestamp_with_rng_and_postprocessor(
    ///     None,
    ///     1,
    ///     &mut rand::thread_rng(),
    ///     Some(&postprocessor_fn),
    /// );
    ///
    /// assert_eq!(0, u128::from(ulid) & 0xFFFF_FFFF);
    /// assert_ne!(0, u128::from(ulid));
    /// ```
    ///
    /// # Panics
    ///
    /// Panics if `timestamp` is larger than `0xFFFF_FFFF_FFFF`.
    #[cfg(feature = "rand")]
    pub fn next_monotonic_from_timestamp_with_rng_and_postprocessor<R>(
        previous_ulid: Option<Self>,
        timestamp: u64,
        rng: &mut R,
        postprocessor: Option<&dyn Fn(Self) -> Self>,
    ) -> Self
    where
        R: rand::Rng,
    {
        if let Some(previous_ulid) = previous_ulid {
            if previous_ulid.timestamp() == timestamp {
                return previous_ulid.increment();
            }
        }

        let result = Self::from_timestamp_with_rng(timestamp, rng);
        postprocessor.map_or(result, |postprocessor| postprocessor(result))
    }

    /// Creates the next strictly monotonic ULID with the given `previous_ulid`, `timestamp`
    /// obtaining randomness from `rng`.
    ///
    /// If the random part of `previous_ulid` would overflow, this function returns `None`.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let previous_ulid = Ulid::from(0);
    /// let ulid = Ulid::next_strictly_monotonic_from_timestamp_with_rng(previous_ulid, 0, &mut rand::thread_rng());
    ///
    /// assert_eq!(ulid, Some(Ulid::from(1)));
    /// ```
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let previous_ulid = Ulid::from(0x0000_0000_0000_FFFF_FFFF_FFFF_FFFF_FFFE);
    /// let ulid = Ulid::next_strictly_monotonic_from_timestamp_with_rng(previous_ulid, 0, &mut rand::thread_rng());
    ///
    /// assert_eq!(ulid, Some(Ulid::from(0x0000_0000_0000_FFFF_FFFF_FFFF_FFFF_FFFF)));
    /// ```
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let previous_ulid = Ulid::from(0x0000_0000_0000_FFFF_FFFF_FFFF_FFFF_FFFF);
    /// let ulid = Ulid::next_strictly_monotonic_from_timestamp_with_rng(previous_ulid, 0, &mut rand::thread_rng());
    ///
    /// // overflow results in None
    /// assert_eq!(ulid, None);
    /// ```
    ///
    /// # Panics
    ///
    /// Panics if `timestamp` is larger than `0xFFFF_FFFF_FFFF`.
    #[cfg(feature = "rand")]
    pub fn next_strictly_monotonic_from_timestamp_with_rng<R>(
        previous_ulid: Self,
        timestamp: u64,
        rng: &mut R,
    ) -> Option<Self>
    where
        R: rand::Rng,
    {
        let result = Self::next_monotonic_from_timestamp_with_rng(previous_ulid, timestamp, rng);

        if previous_ulid < result {
            Some(result)
        } else {
            None
        }
    }

    /// Creates the next strictly monotonic ULID with the given `previous_ulid`, `timestamp`
    /// obtaining randomness from `rng`.
    ///
    /// If the random part of `previous_ulid` would overflow, this function returns `None`.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let previous_ulid = Ulid::from(0);
    /// let ulid = Ulid::next_strictly_monotonic_from_timestamp_with_rng_and_postprocessor(
    ///     Some(previous_ulid),
    ///     0,
    ///     &mut rand::thread_rng(),
    ///     None,
    /// );
    ///
    /// assert_eq!(ulid, Some(Ulid::from(1)));
    /// ```
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let previous_ulid = Ulid::from(0x0000_0000_0000_FFFF_FFFF_FFFF_FFFF_FFFE);
    /// let ulid = Ulid::next_strictly_monotonic_from_timestamp_with_rng_and_postprocessor(
    ///     Some(previous_ulid),
    ///     0,
    ///     &mut rand::thread_rng(),
    ///     None,
    /// );
    ///
    /// assert_eq!(
    ///     ulid,
    ///     Some(Ulid::from(0x0000_0000_0000_FFFF_FFFF_FFFF_FFFF_FFFF))
    /// );
    /// ```
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let previous_ulid = Ulid::from(0x0000_0000_0000_FFFF_FFFF_FFFF_FFFF_FFFF);
    /// let ulid = Ulid::next_strictly_monotonic_from_timestamp_with_rng_and_postprocessor(
    ///     Some(previous_ulid),
    ///     0,
    ///     &mut rand::thread_rng(),
    ///     None,
    /// );
    ///
    /// // overflow results in None
    /// assert_eq!(ulid, None);
    /// ```
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// fn postprocessor_fn(ulid: Ulid) -> Ulid {
    ///     // zero out lowest 32 bits
    ///     Ulid::from(u128::from(ulid) & 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_0000_0000)
    /// }
    ///
    /// let previous_ulid = Ulid::from(0);
    /// let ulid = Ulid::next_strictly_monotonic_from_timestamp_with_rng_and_postprocessor(
    ///     Some(previous_ulid),
    ///     1,
    ///     &mut rand::thread_rng(),
    ///     Some(&postprocessor_fn),
    /// );
    /// let ulid = ulid.unwrap();
    ///
    /// assert_eq!(0, u128::from(ulid) & 0xFFFF_FFFF);
    ///
    /// let ulid = Ulid::next_strictly_monotonic_from_timestamp_with_rng_and_postprocessor(
    ///     None,
    ///     1,
    ///     &mut rand::thread_rng(),
    ///     Some(&postprocessor_fn),
    /// );
    /// let ulid = ulid.unwrap();
    ///
    /// assert_eq!(0, u128::from(ulid) & 0xFFFF_FFFF);
    /// assert_ne!(0, u128::from(ulid));
    /// ```
    ///
    /// # Panics
    ///
    /// Panics if `timestamp` is larger than `0xFFFF_FFFF_FFFF`.
    #[cfg(feature = "rand")]
    pub fn next_strictly_monotonic_from_timestamp_with_rng_and_postprocessor<R>(
        previous_ulid: Option<Self>,
        timestamp: u64,
        rng: &mut R,
        postprocessor: Option<&dyn Fn(Self) -> Self>,
    ) -> Option<Self>
    where
        R: rand::Rng,
    {
        let result = Self::next_monotonic_from_timestamp_with_rng_and_postprocessor(
            previous_ulid,
            timestamp,
            rng,
            postprocessor,
        );

        previous_ulid.map_or(Some(result), |previous_ulid| {
            if previous_ulid < result {
                Some(result)
            } else {
                None
            }
        })
    }

    /// Returns the timestamp of this ULID as number
    /// of non-leap milliseconds since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp").
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    /// use std::str::FromStr;
    ///
    /// let ulid = Ulid::from_str("01CAH7NXGRDJNE9B1NY7PQGYV7")?;
    /// let timestamp = ulid.timestamp();
    ///
    /// assert_eq!(timestamp, 1523144390168);
    /// # Ok::<(), rusty_ulid::DecodingError>(())
    /// ```
    #[must_use]
    pub fn timestamp(&self) -> u64 {
        self.value.0 >> 16
    }

    /// Returns the timestamp of this ULID as a `DateTime<Utc>`.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    /// use std::str::FromStr;
    ///
    /// let ulid = Ulid::from_str("01CAH7NXGRDJNE9B1NY7PQGYV7")?;
    /// let datetime = ulid.datetime();
    ///
    /// assert_eq!(datetime.to_string(), "2018-04-07 23:39:50.168 UTC");
    /// # Ok::<(), rusty_ulid::DecodingError>(())
    /// ```
    #[cfg(feature = "chrono")]
    #[must_use]
    pub fn datetime(&self) -> DateTime<Utc> {
        use chrono::LocalResult;

        match Utc.timestamp_millis_opt(self.timestamp() as i64) {
            LocalResult::Single(dt) => dt,
            _ => panic!("Incorrect timestamp_millis"),
        }
    }

    /// Returns the timestamp of this ULID as a `OffsetDateTime`.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    /// use std::str::FromStr;
    ///
    /// let ulid = Ulid::from_str("01CAH7NXGRDJNE9B1NY7PQGYV7")?;
    /// let datetime = ulid.offsetdatetime();
    ///
    /// assert_eq!(datetime.to_string(), "2018-04-07 23:39:50.168 +00:00:00");
    /// # Ok::<(), rusty_ulid::DecodingError>(())
    /// ```
    #[cfg(feature = "time")]
    #[must_use]
    pub fn offsetdatetime(&self) -> OffsetDateTime {
        OffsetDateTime::from_unix_timestamp_nanos((self.timestamp() * 1_000_000) as i128)
            .expect("invalid or out-of-range datetime")
    }

    /// Returns a new ULID with the random part incremented by one.
    ///
    /// Overflowing the random part resets it to zero without influencing
    /// the timestamp.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let ulid = Ulid::from(0);
    /// let incremented = ulid.increment();
    ///
    /// assert_eq!(incremented, Ulid::from(1));
    /// ```
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let ulid = Ulid::from(0x0000_0000_0000_FFFF_FFFF_FFFF_FFFF_FFFE);
    /// let incremented = ulid.increment();
    ///
    /// assert_eq!(incremented, Ulid::from(0x0000_0000_0000_FFFF_FFFF_FFFF_FFFF_FFFF));
    /// ```
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let ulid = Ulid::from(0x0000_0000_0000_FFFF_FFFF_FFFF_FFFF_FFFF);
    /// let incremented = ulid.increment();
    ///
    /// assert_eq!(incremented, Ulid::from(0));
    /// ```
    #[must_use]
    pub fn increment(self) -> Self {
        const TIMESTAMP_PART_MASK: u128 = 0xFFFF_FFFF_FFFF_0000_0000_0000_0000_0000;
        const RANDOM_PART_MASK: u128 = !TIMESTAMP_PART_MASK;

        let value: u128 = self.into();

        if value & RANDOM_PART_MASK == RANDOM_PART_MASK {
            // overflow, set random part to zero
            (value & TIMESTAMP_PART_MASK).into()
        } else {
            (value + 1).into()
        }
    }

    /// Returns the string representaton of this ULID.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let ulid = Ulid::from(0);
    ///
    /// assert_eq!(ulid.to_string(), "00000000000000000000000000");
    /// ```
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let ulid = Ulid::from(0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF);
    ///
    /// assert_eq!(ulid.to_string(), "7ZZZZZZZZZZZZZZZZZZZZZZZZZ");
    /// ```
    #[allow(clippy::inherent_to_string_shadow_display)]
    // impl fmt::Display is using this method
    // https://github.com/rust-lang/rust-clippy/issues/4396
    #[allow(clippy::wrong_self_convention)]
    // 1.53.0 still requires clippy::wrong_self_convention
    // 1.54.0-beta fixes this false positive
    #[must_use]
    pub fn to_string(&self) -> String {
        let mut string = String::with_capacity(26);

        crockford::append_crockford_u64_tuple(self.value, &mut string);

        string
    }
}

impl fmt::Display for Ulid {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        f.write_str(&self.to_string())
    }
}

impl FromStr for Ulid {
    type Err = DecodingError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let value = crockford::parse_crockford_u64_tuple(s)?;

        Ok(Self { value })
    }
}

impl From<[u8; 16]> for Ulid {
    /// # Examples
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let bytes: [u8; 16] = [
    ///     0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
    ///     0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xF0, 0x0F,
    /// ];
    ///
    /// let ulid = Ulid::from(bytes);
    ///
    /// let expected_ulid = Ulid::from(0x1122_3344_5566_7788_99AA_BBCC_DDEE_F00F);
    ///
    /// assert_eq!(ulid, expected_ulid);
    /// ```
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let bytes: [u8; 16] = [
    ///     0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
    ///     0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xF0, 0x0F,
    /// ];
    ///
    /// let ulid : Ulid = bytes.into();
    ///
    /// let expected_ulid = Ulid::from(0x1122_3344_5566_7788_99AA_BBCC_DDEE_F00F);
    ///
    /// assert_eq!(ulid, expected_ulid);
    /// ```
    #[must_use]
    fn from(bytes: [u8; 16]) -> Self {
        #[rustfmt::skip]
        let high = u64::from(bytes[0]) << 56
            | u64::from(bytes[1]) << 48
            | u64::from(bytes[2]) << 40
            | u64::from(bytes[3]) << 32
            | u64::from(bytes[4]) << 24
            | u64::from(bytes[5]) << 16
            | u64::from(bytes[6]) << 8
            | u64::from(bytes[7]);

        #[rustfmt::skip]
        let low = u64::from(bytes[8]) << 56
            | u64::from(bytes[9]) << 48
            | u64::from(bytes[10]) << 40
            | u64::from(bytes[11]) << 32
            | u64::from(bytes[12]) << 24
            | u64::from(bytes[13]) << 16
            | u64::from(bytes[14]) << 8
            | u64::from(bytes[15]);

        let value = (high, low);
        Self { value }
    }
}

impl From<Ulid> for [u8; 16] {
    /// # Examples
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let ulid = Ulid::from(0x1122_3344_5566_7788_99AA_BBCC_DDEE_F00F);
    ///
    /// let bytes = <[u8; 16]>::from(ulid);
    ///
    /// let expected_bytes: [u8; 16] = [
    ///     0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
    ///     0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xF0, 0x0F,
    /// ];
    ///
    /// assert_eq!(bytes, expected_bytes);
    /// ```
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let ulid = Ulid::from(0x1122_3344_5566_7788_99AA_BBCC_DDEE_F00F);
    ///
    /// let bytes: [u8; 16] = ulid.into();
    ///
    /// let expected_bytes: [u8; 16] = [
    ///     0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
    ///     0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xF0, 0x0F,
    /// ];
    ///
    /// assert_eq!(bytes, expected_bytes);
    /// ```
    #[rustfmt::skip]
    #[must_use]
    fn from(ulid: Ulid) -> Self {
        let value = ulid.value;

        [
            ((value.0 >> 56) & 0xFF) as u8,
            ((value.0 >> 48) & 0xFF) as u8,
            ((value.0 >> 40) & 0xFF) as u8,
            ((value.0 >> 32) & 0xFF) as u8,
            ((value.0 >> 24) & 0xFF) as u8,
            ((value.0 >> 16) & 0xFF) as u8,
            ((value.0 >> 8) & 0xFF) as u8,
            (value.0 & 0xFF) as u8,
            ((value.1 >> 56) & 0xFF) as u8,
            ((value.1 >> 48) & 0xFF) as u8,
            ((value.1 >> 40) & 0xFF) as u8,
            ((value.1 >> 32) & 0xFF) as u8,
            ((value.1 >> 24) & 0xFF) as u8,
            ((value.1 >> 16) & 0xFF) as u8,
            ((value.1 >> 8) & 0xFF) as u8,
            (value.1 & 0xFF) as u8,
        ]
    }
}

impl From<(u64, u64)> for Ulid {
    /// # Examples
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let tuple = (0x1122_3344_5566_7788, 0x99AA_BBCC_DDEE_F00F);
    ///
    /// let ulid = Ulid::from(tuple);
    ///
    /// let expected_ulid = Ulid::from(0x1122_3344_5566_7788_99AA_BBCC_DDEE_F00F);
    ///
    /// assert_eq!(ulid, expected_ulid);
    /// ```
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let tuple = (0x1122_3344_5566_7788, 0x99AA_BBCC_DDEE_F00F);
    ///
    /// let ulid : Ulid = tuple.into();
    ///
    /// let expected_ulid = Ulid::from(0x1122_3344_5566_7788_99AA_BBCC_DDEE_F00F);
    ///
    /// assert_eq!(ulid, expected_ulid);
    /// ```
    #[must_use]
    fn from(value: (u64, u64)) -> Self {
        Self { value }
    }
}

impl From<Ulid> for (u64, u64) {
    /// # Examples
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let ulid = Ulid::from(0x1122_3344_5566_7788_99AA_BBCC_DDEE_F00F);
    ///
    /// let tuple = <(u64, u64)>::from(ulid);
    ///
    /// let expected_tuple = (0x1122_3344_5566_7788, 0x99AA_BBCC_DDEE_F00F);
    ///
    /// assert_eq!(tuple, expected_tuple);
    /// ```
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let ulid = Ulid::from(0x1122_3344_5566_7788_99AA_BBCC_DDEE_F00F);
    ///
    /// let tuple : (u64, u64) = ulid.into();
    ///
    /// let expected_tuple = (0x1122_3344_5566_7788, 0x99AA_BBCC_DDEE_F00F);
    ///
    /// assert_eq!(tuple, expected_tuple);
    /// ```
    #[must_use]
    fn from(ulid: Ulid) -> Self {
        ulid.value
    }
}

impl From<u128> for Ulid {
    /// # Examples
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let value = 0x1122_3344_5566_7788_99AA_BBCC_DDEE_F00F;
    ///
    /// let ulid = Ulid::from(value);
    ///
    /// let expected_ulid = Ulid::from((0x1122_3344_5566_7788, 0x99AA_BBCC_DDEE_F00F));
    ///
    /// assert_eq!(ulid, expected_ulid);
    /// ```
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let value = 0x1122_3344_5566_7788_99AA_BBCC_DDEE_F00F;
    ///
    /// let ulid : Ulid = value.into();
    ///
    /// let expected_ulid = Ulid::from((0x1122_3344_5566_7788, 0x99AA_BBCC_DDEE_F00F));
    ///
    /// assert_eq!(ulid, expected_ulid);
    /// ```
    #[must_use]
    fn from(value: u128) -> Self {
        let value = ((value >> 64) as u64, (value & 0xFFFF_FFFF_FFFF_FFFF) as u64);
        Self { value }
    }
}

impl From<Ulid> for u128 {
    /// # Examples
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let ulid = Ulid::from((0x1122_3344_5566_7788, 0x99AA_BBCC_DDEE_F00F));
    ///
    /// let value = <u128>::from(ulid);
    ///
    /// let expected_value = 0x1122_3344_5566_7788_99AA_BBCC_DDEE_F00F;
    ///
    /// assert_eq!(value, expected_value);
    /// ```
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    ///
    /// let ulid = Ulid::from((0x1122_3344_5566_7788, 0x99AA_BBCC_DDEE_F00F));
    ///
    /// let value : u128 = ulid.into();
    ///
    /// let expected_value = 0x1122_3344_5566_7788_99AA_BBCC_DDEE_F00F;
    ///
    /// assert_eq!(value, expected_value);
    /// ```
    #[must_use]
    fn from(ulid: Ulid) -> Self {
        Self::from(ulid.value.0) << 64 | Self::from(ulid.value.1)
    }
}

impl TryFrom<&[u8]> for Ulid {
    type Error = DecodingError;

    /// Returns a ULID for the given slice of bytes or `DecodingError::InvalidLength`
    /// if the slice does not contain exactly 16 bytes.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    /// use std::convert::TryFrom;
    /// use std::convert::TryInto;
    ///
    /// let bytes: [u8; 18] = [
    ///     0x00,
    ///     0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
    ///     0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xF0, 0x0F,
    ///     0x00,
    /// ];
    ///
    /// let ulid : Ulid = Ulid::try_from(&bytes[1..17])?;
    ///
    /// let expected_ulid = Ulid::from(0x1122_3344_5566_7788_99AA_BBCC_DDEE_F00F);
    ///
    /// assert_eq!(ulid, expected_ulid);
    ///
    /// let ulid : Ulid = (&bytes[1..17]).try_into()?;
    ///
    /// let expected_ulid = Ulid::from(0x1122_3344_5566_7788_99AA_BBCC_DDEE_F00F);
    ///
    /// assert_eq!(ulid, expected_ulid);
    /// # Ok::<(), rusty_ulid::DecodingError>(())
    /// ```
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    /// use rusty_ulid::DecodingError;
    /// use std::convert::TryFrom;
    ///
    /// let mut bytes: [u8; 17] = [0; 17];
    /// let result = Ulid::try_from(&bytes[0..]);
    ///
    /// assert_eq!(result, Err(DecodingError::InvalidLength))
    /// ```
    ///
    /// ```
    /// use rusty_ulid::Ulid;
    /// use rusty_ulid::DecodingError;
    /// use std::convert::TryFrom;
    ///
    /// let mut bytes: [u8; 15] = [0; 15];
    /// let result = Ulid::try_from(&bytes[0..]);
    ///
    /// assert_eq!(result, Err(DecodingError::InvalidLength))
    /// ```
    fn try_from(bytes: &[u8]) -> Result<Self, DecodingError> {
        if bytes.len() != 16 {
            return Err(DecodingError::InvalidLength);
        }

        #[rustfmt::skip]
        let high = u64::from(bytes[0]) << 56
            | u64::from(bytes[1]) << 48
            | u64::from(bytes[2]) << 40
            | u64::from(bytes[3]) << 32
            | u64::from(bytes[4]) << 24
            | u64::from(bytes[5]) << 16
            | u64::from(bytes[6]) << 8
            | u64::from(bytes[7]);

        #[rustfmt::skip]
        let low = u64::from(bytes[8]) << 56
            | u64::from(bytes[9]) << 48
            | u64::from(bytes[10]) << 40
            | u64::from(bytes[11]) << 32
            | u64::from(bytes[12]) << 24
            | u64::from(bytes[13]) << 16
            | u64::from(bytes[14]) << 8
            | u64::from(bytes[15]);

        let value = (high, low);
        Ok(Self { value })
    }
}

#[cfg(feature = "serde")]
impl Serialize for Ulid {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        if serializer.is_human_readable() {
            serializer.serialize_str(&self.to_string())
        } else {
            let bytes: [u8; 16] = (*self).into();
            serializer.serialize_bytes(&bytes)
        }
    }
}

#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for Ulid {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        if deserializer.is_human_readable() {
            struct UlidStringVisitor;

            impl<'vi> de::Visitor<'vi> for UlidStringVisitor {
                type Value = Ulid;

                fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
                    write!(formatter, "a ULID string")
                }

                fn visit_str<E: de::Error>(self, value: &str) -> Result<Ulid, E> {
                    value.parse::<Ulid>().map_err(E::custom)
                }
            }

            deserializer.deserialize_str(UlidStringVisitor)
        } else {
            struct UlidBytesVisitor;

            impl<'vi> de::Visitor<'vi> for UlidBytesVisitor {
                type Value = Ulid;

                fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
                    write!(formatter, "16 ULID bytes")
                }

                fn visit_bytes<E: de::Error>(self, value: &[u8]) -> Result<Ulid, E> {
                    Ulid::try_from(value).map_err(E::custom)
                }
            }
            deserializer.deserialize_bytes(UlidBytesVisitor)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    const PAST_TIMESTAMP: u64 = 1_481_195_424_879;
    const PAST_TIMESTAMP_PART: &str = "01B3F2133F";

    const MAX_TIMESTAMP: u64 = 0xFFFF_FFFF_FFFF;
    const MAX_TIMESTAMP_PART: &str = "7ZZZZZZZZZ";

    const MIN_TIMESTAMP: u64 = 0;
    const MIN_TIMESTAMP_PART: &str = "0000000000";

    #[test]
    fn increment() {
        single_increment(0x0000_0000_0000_0000_0000_0000_0000_0000, Ulid::from(1));
        single_increment(
            0x0000_0000_0000_FFFF_FFFF_FFFF_FFFF_FFFE,
            Ulid::from(0xFFFF_FFFF_FFFF_FFFF_FFFF),
        );
        single_increment(0x0000_0000_0000_FFFF_FFFF_FFFF_FFFF_FFFF, Ulid::from(0));
        single_increment(
            0x0000_0000_0001_0000_0000_0000_0000_0000,
            Ulid::from(0x0000_0000_0001_0000_0000_0000_0000_0001),
        );
        single_increment(
            0x0000_0000_0001_FFFF_FFFF_FFFF_FFFF_FFFF,
            Ulid::from(0x0000_0000_0001_0000_0000_0000_0000_0000),
        );
    }

    fn single_increment(input: u128, expected_result: Ulid) {
        let input_value: Ulid = input.into();
        let incremented = input_value.increment();

        assert_eq!(incremented, expected_result);
        assert_eq!(input_value.timestamp(), incremented.timestamp());
    }

    #[test]
    fn from_string_to_string() {
        single_from_string_to_string(
            &(PAST_TIMESTAMP_PART.to_owned() + "0000000000000000"),
            PAST_TIMESTAMP,
        );
        single_from_string_to_string(
            &(PAST_TIMESTAMP_PART.to_owned() + "ZZZZZZZZZZZZZZZZ"),
            PAST_TIMESTAMP,
        );
        single_from_string_to_string(
            &(PAST_TIMESTAMP_PART.to_owned() + "123456789ABCDEFG"),
            PAST_TIMESTAMP,
        );
        single_from_string_to_string(
            &(PAST_TIMESTAMP_PART.to_owned() + "1000000000000000"),
            PAST_TIMESTAMP,
        );
        single_from_string_to_string(
            &(PAST_TIMESTAMP_PART.to_owned() + "1000000000000001"),
            PAST_TIMESTAMP,
        );
        single_from_string_to_string(
            &(PAST_TIMESTAMP_PART.to_owned() + "0001000000000001"),
            PAST_TIMESTAMP,
        );
        single_from_string_to_string(
            &(PAST_TIMESTAMP_PART.to_owned() + "0100000000000001"),
            PAST_TIMESTAMP,
        );
        single_from_string_to_string(
            &(PAST_TIMESTAMP_PART.to_owned() + "0000000000000001"),
            PAST_TIMESTAMP,
        );
        single_from_string_to_string(
            &(MAX_TIMESTAMP_PART.to_owned() + "123456789ABCDEFG"),
            MAX_TIMESTAMP,
        );
        single_from_string_to_string(
            &(MIN_TIMESTAMP_PART.to_owned() + "123456789ABCDEFG"),
            MIN_TIMESTAMP,
        );

        let largest_legal_ulid_string = "7ZZZZZZZZZZZZZZZZZZZZZZZZZ";
        single_from_string_to_string(largest_legal_ulid_string, MAX_TIMESTAMP);
    }

    fn single_from_string_to_string(s: &str, timestamp: u64) {
        let ulid = Ulid::from_str(s).unwrap();
        assert_eq!(ulid.timestamp(), timestamp);
        assert_eq!(ulid.to_string(), s);
    }

    #[test]
    fn from_string_to_string_special_cases() {
        single_from_string_to_string_special_case(
            &(PAST_TIMESTAMP_PART.to_owned() + "00i0000000000000"),
            &(PAST_TIMESTAMP_PART.to_owned() + "0010000000000000"),
            PAST_TIMESTAMP,
        );
        single_from_string_to_string_special_case(
            &(PAST_TIMESTAMP_PART.to_owned() + "00I0000000000000"),
            &(PAST_TIMESTAMP_PART.to_owned() + "0010000000000000"),
            PAST_TIMESTAMP,
        );
        single_from_string_to_string_special_case(
            &(PAST_TIMESTAMP_PART.to_owned() + "00l0000000000000"),
            &(PAST_TIMESTAMP_PART.to_owned() + "0010000000000000"),
            PAST_TIMESTAMP,
        );
        single_from_string_to_string_special_case(
            &(PAST_TIMESTAMP_PART.to_owned() + "00L0000000000000"),
            &(PAST_TIMESTAMP_PART.to_owned() + "0010000000000000"),
            PAST_TIMESTAMP,
        );
        single_from_string_to_string_special_case(
            &(PAST_TIMESTAMP_PART.to_owned() + "00o0000000000000"),
            &(PAST_TIMESTAMP_PART.to_owned() + "0000000000000000"),
            PAST_TIMESTAMP,
        );
        single_from_string_to_string_special_case(
            &(PAST_TIMESTAMP_PART.to_owned() + "00O0000000000000"),
            &(PAST_TIMESTAMP_PART.to_owned() + "0000000000000000"),
            PAST_TIMESTAMP,
        );
    }

    fn single_from_string_to_string_special_case(s: &str, expected: &str, timestamp: u64) {
        let ulid = Ulid::from_str(s).unwrap();
        assert_eq!(ulid.timestamp(), timestamp);
        assert_eq!(ulid.to_string(), expected);
    }

    #[test]
    fn from_str_failure_too_long() {
        let result = Ulid::from_str("123456789012345678901234567");
        assert_eq!(result, Err(DecodingError::InvalidLength));
    }

    #[test]
    fn from_str_failure_too_short() {
        let result = Ulid::from_str("1234567890123456789012345");
        assert_eq!(result, Err(DecodingError::InvalidLength));
    }

    #[test]
    fn from_str_failure_invalid_unicode() {
        let string = "012345678🦀0123456789012";
        let result = Ulid::from_str(string);
        assert_eq!(result, Err(DecodingError::InvalidChar('🦀')));
    }

    #[test]
    fn from_str_failure_overflow() {
        let smallest_overflowing_ulid_string = "80000000000000000000000000";
        let result = Ulid::from_str(smallest_overflowing_ulid_string);
        assert_eq!(result, Err(DecodingError::DataTypeOverflow));
    }

    #[test]
    fn eq_cmp_sanity_checks() {
        // yes, this is pretty paranoid.

        use std::cmp::Ordering;

        let ulid_one_low: Ulid = (0, 1).into();
        let ulid_two_low: Ulid = (0, 2).into();
        let ulid_one_high: Ulid = (1, 0).into();

        let ulid_one_low_other: Ulid = (0, 1).into();

        assert!(ulid_one_low.eq(&ulid_one_low));
        assert_eq!(ulid_one_low.cmp(&ulid_one_low), Ordering::Equal);

        assert_eq!(ulid_one_low, ulid_one_low_other);
        assert!(ulid_one_low.eq(&ulid_one_low_other));
        assert_eq!(ulid_one_low.cmp(&ulid_one_low_other), Ordering::Equal);

        assert_ne!(ulid_one_low, ulid_two_low);
        assert_ne!(ulid_two_low, ulid_one_low);
        assert!(ulid_one_low < ulid_two_low);
        assert!(ulid_two_low > ulid_one_low);
        assert!(!ulid_one_low.eq(&ulid_two_low));
        assert!(!ulid_two_low.eq(&ulid_one_low));
        assert_eq!(ulid_one_low.cmp(&ulid_two_low), Ordering::Less);
        assert_eq!(ulid_two_low.cmp(&ulid_one_low), Ordering::Greater);

        assert_ne!(ulid_one_low, ulid_one_high);
        assert_ne!(ulid_one_high, ulid_one_low);
        assert!(!ulid_one_low.eq(&ulid_one_high));
        assert!(!ulid_one_high.eq(&ulid_one_low));
        assert_eq!(ulid_one_low.cmp(&ulid_one_high), Ordering::Less);
        assert_eq!(ulid_one_high.cmp(&ulid_one_low), Ordering::Greater);
    }

    #[test]
    fn hash_sanity_checks() {
        // yes, this is also pretty paranoid.

        use std::collections::hash_map::DefaultHasher;
        use std::hash::{Hash, Hasher};

        let ulid_one_low: Ulid = (0, 1).into();
        let ulid_two_low: Ulid = (0, 2).into();
        let ulid_one_high: Ulid = (1, 0).into();

        let ulid_one_low_other: Ulid = (0, 1).into();

        let mut hasher_one_low = DefaultHasher::new();
        ulid_one_low.hash(&mut hasher_one_low);
        let hash_one_low = hasher_one_low.finish();

        let mut hasher_one_low_other = DefaultHasher::new();
        ulid_one_low_other.hash(&mut hasher_one_low_other);
        let hash_one_low_other = hasher_one_low_other.finish();

        let mut hasher_two_low = DefaultHasher::new();
        ulid_two_low.hash(&mut hasher_two_low);
        let hash_two_low = hasher_two_low.finish();

        let mut hasher_one_high = DefaultHasher::new();
        ulid_one_high.hash(&mut hasher_one_high);
        let hash_one_high = hasher_one_high.finish();

        // this must be true
        assert_eq!(hash_one_low, hash_one_low_other);

        // this should be true in case of a reasonable DefaultHasher implementation
        assert_ne!(hash_one_low, hash_two_low);
        assert_ne!(hash_one_low, hash_one_high);
    }

    #[cfg(not(miri))] // expected panic
    #[cfg(feature = "rand")]
    #[test]
    #[should_panic(expected = "ULID does not support timestamps after +10889-08-02T05:31:50.655Z")]
    fn y10889_bug() {
        use rand::rngs::mock::StepRng;

        let mut mock_rng = StepRng::new(0, 0);
        let _ = Ulid::from_timestamp_with_rng(0x0001_0000_0000_0000, &mut mock_rng);
    }

    #[cfg(feature = "rand")]
    #[test]
    fn test_from_timestamp_with_rng() {
        use rand::rngs::mock::StepRng;

        let mut mock_rng = StepRng::new(0, 0);
        let ulid = Ulid::from_timestamp_with_rng(0xFFFF_FFFF_FFFF, &mut mock_rng);

        let ulid_value: u128 = ulid.into();

        assert_eq!(ulid_value, 0xFFFF_FFFF_FFFF_0000_0000_0000_0000_0000);

        let mut mock_rng = StepRng::new(0xF00F, 0);
        let ulid = Ulid::from_timestamp_with_rng(0, &mut mock_rng);

        let ulid_value: u128 = ulid.into();

        assert_eq!(ulid_value, 0x0000_0000_0000_F00F_0000_0000_0000_F00F);
    }

    #[cfg(feature = "rand")]
    #[test]
    fn test_next_monotonic_from_timestamp_with_rng_and_postprocessor() {
        fn postprocessor_fn(ulid: Ulid) -> Ulid {
            // zero out lowest 32 bits
            Ulid::from(u128::from(ulid) & 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_0000_0000)
        }

        let previous_ulid = Ulid::from(0);
        let ulid = Ulid::next_monotonic_from_timestamp_with_rng_and_postprocessor(
            Some(previous_ulid),
            1,
            &mut rand::thread_rng(),
            Some(&postprocessor_fn),
        );

        assert_eq!(0, u128::from(ulid) & 0xFFFF_FFFF);

        let ulid = Ulid::next_monotonic_from_timestamp_with_rng_and_postprocessor(
            None,
            1,
            &mut rand::thread_rng(),
            Some(&postprocessor_fn),
        );

        assert_eq!(0, u128::from(ulid) & 0xFFFF_FFFF);
        assert_ne!(0, u128::from(ulid));
    }

    #[cfg(feature = "rand")]
    #[test]
    fn test_next_strictly_monotonic_from_timestamp_with_rng_and_postprocessor_overflow() {
        let previous_ulid = Ulid::from(0);
        let ulid = Ulid::next_strictly_monotonic_from_timestamp_with_rng_and_postprocessor(
            Some(previous_ulid),
            0,
            &mut rand::thread_rng(),
            None,
        );

        assert_eq!(ulid, Some(Ulid::from(1)));

        let previous_ulid = Ulid::from(0x0000_0000_0000_FFFF_FFFF_FFFF_FFFF_FFFE);
        let ulid = Ulid::next_strictly_monotonic_from_timestamp_with_rng_and_postprocessor(
            Some(previous_ulid),
            0,
            &mut rand::thread_rng(),
            None,
        );

        assert_eq!(
            ulid,
            Some(Ulid::from(0x0000_0000_0000_FFFF_FFFF_FFFF_FFFF_FFFF))
        );

        let previous_ulid = Ulid::from(0x0000_0000_0000_FFFF_FFFF_FFFF_FFFF_FFFF);
        let ulid = Ulid::next_strictly_monotonic_from_timestamp_with_rng_and_postprocessor(
            Some(previous_ulid),
            0,
            &mut rand::thread_rng(),
            None,
        );

        // overflow results in None
        assert_eq!(ulid, None);
    }

    #[cfg(feature = "rand")]
    #[test]
    fn test_next_strictly_monotonic_from_timestamp_with_rng_and_postprocessor() {
        fn postprocessor_fn(ulid: Ulid) -> Ulid {
            // zero out lowest 32 bits
            Ulid::from(u128::from(ulid) & 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_0000_0000)
        }

        let previous_ulid = Ulid::from(0);
        let ulid = Ulid::next_strictly_monotonic_from_timestamp_with_rng_and_postprocessor(
            Some(previous_ulid),
            1,
            &mut rand::thread_rng(),
            Some(&postprocessor_fn),
        );
        let ulid = ulid.unwrap();

        assert_eq!(0, u128::from(ulid) & 0xFFFF_FFFF);

        let ulid = Ulid::next_strictly_monotonic_from_timestamp_with_rng_and_postprocessor(
            None,
            1,
            &mut rand::thread_rng(),
            Some(&postprocessor_fn),
        );
        let ulid = ulid.unwrap();

        assert_eq!(0, u128::from(ulid) & 0xFFFF_FFFF);
        assert_ne!(0, u128::from(ulid));
    }
}

#[cfg(all(doctest, feature = "rand", feature = "chrono"))]
mod doc_tests {
    use doc_comment::doctest;
    doctest!("../README.md", readme);
}

#[cfg(all(test, feature = "serde"))]
mod serde_tests {
    use super::*;
    use serde_test::{assert_de_tokens_error, assert_tokens, Compact, Readable, Token};

    #[test]
    fn test_serde_readable() {
        use serde_test::Configure;

        let ulid = Ulid::from_str("7ZZZZZZZZZZZZZZZZZZZZZZZZZ").unwrap();
        assert_tokens(
            &ulid.readable(),
            &[Token::Str("7ZZZZZZZZZZZZZZZZZZZZZZZZZ")],
        );

        let ulid = Ulid::from(0x1122_3344_5566_7788_99AA_BBCC_DDEE_F00F);
        assert_tokens(
            &ulid.readable(),
            &[Token::Str("0H48SM8NB6EY49KANVSKEYXW0F")],
        );
    }

    #[test]
    fn test_serde_compact() {
        use serde_test::Configure;

        let ulid = Ulid::from_str("7ZZZZZZZZZZZZZZZZZZZZZZZZZ").unwrap();
        assert_tokens(
            &ulid.compact(),
            &[Token::Bytes(&[
                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                0xFF, 0xFF,
            ])],
        );

        let ulid = Ulid::from(0x1122_3344_5566_7788_99AA_BBCC_DDEE_F00F);
        assert_tokens(
            &ulid.compact(),
            &[Token::Bytes(&[
                0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE,
                0xF0, 0x0F,
            ])],
        );
    }

    #[test]
    fn test_de_readable_error() {
        assert_de_tokens_error::<Readable<Ulid>>(
            &[Token::Bytes(&[
                0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE,
                0xF0, 0x0F,
            ])],
            "invalid type: byte array, expected a ULID string",
        );

        assert_de_tokens_error::<Readable<Ulid>>(
            &[Token::Str("0H48SM8NB6EY49KANUSKEYXW0F")],
            "invalid character 'U'",
        );

        assert_de_tokens_error::<Readable<Ulid>>(
            &[Token::Str("0H48SM8NB6EY49KANVSKEYXW0FF")],
            "invalid length",
        );

        assert_de_tokens_error::<Readable<Ulid>>(
            &[Token::Str("0H48SM8NB6EY49KANVSKEYXW0")],
            "invalid length",
        );

        assert_de_tokens_error::<Readable<Ulid>>(
            &[Token::Str("80000000000000000000000000")],
            "data type overflow",
        );
    }

    #[test]
    fn test_de_compact_error() {
        assert_de_tokens_error::<Compact<Ulid>>(
            &[Token::Str("0H48SM8NB6EY49KANVSKEYXW0F")],
            "invalid type: string \"0H48SM8NB6EY49KANVSKEYXW0F\", expected 16 ULID bytes",
        );

        assert_de_tokens_error::<Compact<Ulid>>(
            &[Token::Bytes(&[
                0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE,
                0xF0, 0x0F, 0xFF,
            ])],
            "invalid length",
        );

        assert_de_tokens_error::<Compact<Ulid>>(
            &[Token::Bytes(&[
                0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE,
                0xF0,
            ])],
            "invalid length",
        );
    }
}