Skip to main content

nifty_download/
id.rs

1//! The ids that name downloads to code, such as `download-3`.
2
3use std::fmt;
4use std::sync::atomic::{AtomicU64, Ordering};
5
6/// What every id starts with, so an id reads as one and not as a count.
7const PREFIX: &str = "download-";
8
9/// Ids are counted for the whole process, so after `nf dev` reloads a program, a new
10/// download never gets the id of one from before, which state may still hold.
11static NEXT: AtomicU64 = AtomicU64::new(1);
12
13/// A download's id, unique for as long as the process runs.
14#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
15pub struct DownloadId(u64);
16
17impl DownloadId {
18    /// An id no download has had yet.
19    #[must_use]
20    pub fn next() -> Self {
21        Self(NEXT.fetch_add(1, Ordering::Relaxed))
22    }
23
24    /// The id `text` shows, if it is one.
25    #[must_use]
26    pub fn parse(text: &str) -> Option<Self> {
27        text.strip_prefix(PREFIX)?.parse().ok().map(Self)
28    }
29}
30
31impl fmt::Display for DownloadId {
32    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33        write!(f, "{PREFIX}{}", self.0)
34    }
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40
41    #[test]
42    fn reads_back_the_ids_it_shows() {
43        let id = DownloadId::next();
44        assert_ne!(DownloadId::next(), id);
45        assert_eq!(DownloadId::parse(&id.to_string()), Some(id));
46        assert_eq!(DownloadId::parse("download-x"), None);
47        assert_eq!(DownloadId::parse("7"), None);
48        assert_eq!(DownloadId::parse(""), None);
49    }
50}