sequence-generator-rust 0.3.1

Customizable 64-bit unique distributed IDs sequence generator based on Twitter's ID (snowflake). Build in Rust
Documentation
use ::sequence_generator::*;
use std::convert::TryFrom;
use std::env;
use std::path::Path;
use std::rc::Rc;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use structopt::StructOpt;
use time::{format_description::well_known::Rfc3339, OffsetDateTime};

#[derive(Debug, StructOpt)]
struct Opt {
    #[structopt(default_value = "1", long, short)]
    number: usize,
    #[structopt(long, short)]
    custom_epoch: Option<String>,
    #[structopt(long)]
    micros_ten_power: Option<u8>,
    #[structopt(long)]
    node_id_bits: Option<u8>,
    #[structopt(long)]
    sequence_bits: Option<u8>,
    #[structopt(long)]
    node_id: Option<u16>,
    #[structopt(long)]
    unused_bits: Option<u8>,
    #[structopt(default_value = ".env", long)]
    dotenv_file: String,
    #[structopt(long)]
    cooldown_ns: Option<u64>,
    #[structopt(long, short)]
    debug: bool,
}

fn main() {
    let mut args = Opt::from_args();
    let dotenv_file = &args.dotenv_file;
    if Path::new(dotenv_file).exists() {
        dotenv::from_filename(dotenv_file).unwrap_or_else(|_| {
            panic!(
                "Error: Could not retrieve environment variables from configuration file '{}'",
                dotenv_file
            )
        });
        for (key, value) in env::vars() {
            if key == "CUSTOM_EPOCH" && !value.is_empty() && args.custom_epoch.is_none() {
                args.custom_epoch = Some(value.parse::<String>().unwrap_or_else(|_| {panic!(
                    "Error: Couldn't parse value CUSTOM_EPOCH '{}' as String, invalid UTF-8 characters", value)
                }));
            }
            if key == "NODE_ID_BITS" && !value.is_empty() && args.node_id_bits.is_none() {
                args.node_id_bits = Some(value.parse::<u8>().unwrap_or_else(|_| {
                    panic!(
                    "Error: NODE_ID_BITS '{}' couldn't be interpreted as value between 0 and 64",
                    value
                )
                }));
            }
            if key == "SEQUENCE_BITS" && !value.is_empty() && args.sequence_bits.is_none() {
                args.sequence_bits = Some(value.parse::<u8>().unwrap_or_else(|_| {
                    panic!(
                    "Error: SEQUENCE_BITS '{}' couldn't be interpreted as value between 0 and 64",
                    value
                )
                }));
            }
            if key == "MICROS_TEN_POWER" && !value.is_empty() && args.micros_ten_power.is_none() {
                args.micros_ten_power = Some(value.parse::<u8>().unwrap_or_else(|_| {panic!(
                    "Error: MICROS_TEN_POWER '{}' couldn't be interpreted as value between 0 and 64", value)
                }));
            }
            if key == "UNUSED_BITS" && !value.is_empty() && args.unused_bits.is_none() {
                args.unused_bits = Some(value.parse::<u8>().unwrap_or_else(|_| {
                    panic!(
                        "Error: UNUSED_BITS '{}' couldn't be interpreted as value between 0 and 64",
                        value
                    )
                }));
            }
            if key == "COOLDOWN_NS" && !value.is_empty() && args.cooldown_ns.is_none() {
                args.cooldown_ns = Some(value.parse::<u64>().unwrap_or_else(|_| {
                    panic!(
                    "Error: COOLDOWN_NS '{}' couldn't be interpreted as an unsigned integer value",
                    value
                )
                }));
            }
        }
    }
    if args.custom_epoch.is_none() {
        args.custom_epoch = Some("2020-01-01T00:00:00Z".to_owned());
    }

    if args.micros_ten_power.is_none() {
        args.micros_ten_power = Some(2_u8);
    }

    if args.node_id_bits.is_none() {
        args.node_id_bits = Some(9_u8);
    }

    if args.sequence_bits.is_none() {
        args.sequence_bits = Some(11_u8);
    }

    if args.node_id.is_none() {
        args.node_id = Some(0_u16);
    }

    if args.unused_bits.is_none() {
        args.unused_bits = Some(0_u8);
    }

    if args.cooldown_ns.is_none() {
        args.cooldown_ns = Some(1500_u64);
    }

    let custom_epoch_millis_i128 =
        OffsetDateTime::parse(args.custom_epoch.as_ref().unwrap(), &Rfc3339)
            .unwrap_or_else(|_| {
                panic!(
                    "Error: Could not parse CUSTOM_EPOCH '{}' as an RFC-3339/ISO-8601 datetime.",
                    args.custom_epoch.as_ref().unwrap()
                )
            })
            .unix_timestamp_nanos()
            / 1000000;
    let custom_epoch_millis = i64::try_from(custom_epoch_millis_i128).unwrap();
    let custom_epoch = UNIX_EPOCH
        .checked_add(Duration::from_millis(custom_epoch_millis as u64))
        .unwrap_or_else(|| {
            panic!(
            "Error: Could not generate a SystemTime custom epoch from milliseconds timestamp '{}'",
            custom_epoch_millis
        )
        });
    let properties = Rc::new(sequence_generator::SequenceProperties::new(
        custom_epoch,
        args.node_id_bits.unwrap(),
        args.node_id.unwrap(),
        args.sequence_bits.unwrap(),
        args.micros_ten_power.unwrap(),
        args.unused_bits.unwrap(),
        args.cooldown_ns.unwrap(),
    ));
    let mut vector_ids: Vec<u64> = vec![0; args.number];
    if args.debug {
        let time_now = SystemTime::now();
        for element in vector_ids.iter_mut() {
            *element = sequence_generator::generate_id(&properties).unwrap_or_else(
                |error| {
                    panic!(
                        "SequenceGeneratorError: Failed to get ID from properties {:?}. SystemTimeError difference {:?}",
                        properties,
                        (error).duration()
                    )
                }
            );
        }
        let elapsed = time_now
            .elapsed()
            .expect("Error: Failed to get elapsed time.")
            .as_nanos();
        for (index, element) in vector_ids.into_iter().enumerate() {
            println!("{}: {}", index, element);
        }
        println!("It took {:?} nanoseconds", elapsed);
    } else {
        for (index, element) in vector_ids.iter_mut().enumerate() {
            *element = sequence_generator::generate_id(&properties).unwrap_or_else(
                |error| {
                    panic!(
                        "SequenceGeneratorError: Failed to get ID from properties {:?}. SystemTimeError difference {:?}",
                        properties,
                        (error).duration()
                    )
                });
            println!("{}: {}", index, element);
        }
    }
}