diff options
author | Lars Wirzenius <liw@liw.fi> | 2020-09-17 08:09:23 +0300 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2020-09-17 08:09:23 +0300 |
commit | 266b00a00a6a245464b6a4918f98ea55fcba286b (patch) | |
tree | 68683d2fcd01d6bf11cd16783248ce08fae8b8e6 /src/chunkid.rs | |
parent | 80e9c8f81da572278dd5f5218e6db23cd2900d0e (diff) | |
download | obnam2-266b00a00a6a245464b6a4918f98ea55fcba286b.tar.gz |
feat: add an initial ChunkId implementation
Diffstat (limited to 'src/chunkid.rs')
-rw-r--r-- | src/chunkid.rs | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/src/chunkid.rs b/src/chunkid.rs new file mode 100644 index 0000000..f3af7cf --- /dev/null +++ b/src/chunkid.rs @@ -0,0 +1,83 @@ +use std::fmt; +use std::str::FromStr; +use uuid::Uuid; + +/// An identifier for a chunk. +/// +/// An identifier is chosen randomly in such a way that even in +/// extremely large numbers of identifiers the likelihood of duplicate +/// identifiers is so small it can be ignored. The current +/// implementation uses UUID4 and provides a 122-bit random number. +/// For a discussion on collision likelihood, see +/// <https://en.wikipedia.org/wiki/Universally_unique_identifier#Collisions>. +/// +/// We also need to be able to re-create identifiers from stored +/// values. When an identifier is formatted as a string and parsed +/// back, the result is the same value. +/// +/// Because every identifier is meant to be different, there is no +/// default value, since default values should be identical. +#[derive(Debug, PartialEq)] +pub struct ChunkId { + id: String, +} + +#[allow(clippy::new_without_default)] +impl ChunkId { + /// Construct a new, random identifier. + pub fn new() -> Self { + ChunkId { + id: Uuid::new_v4().to_string(), + } + } +} + +impl fmt::Display for ChunkId { + /// Format an identifier for display. + /// + /// The output can be parsed to re-created an identical identifier. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.id) + } +} + +impl FromStr for ChunkId { + type Err = (); + + /// Parse a string representation of an identifier. + fn from_str(s: &str) -> Result<Self, Self::Err> { + Ok(ChunkId { id: s.to_string() }) + } +} + +#[cfg(test)] +mod test { + use super::ChunkId; + + #[test] + fn displayable() { + let id = ChunkId::new(); + assert_ne!(format!("{}", id), "") + } + + #[test] + fn never_the_same() { + let id1 = ChunkId::new(); + let id2 = ChunkId::new(); + assert_ne!(id1, id2); + } + + #[test] + fn recreatable() { + let id_str = "xyzzy"; // it doesn't matter what the string representation is + let id: ChunkId = id_str.parse().unwrap(); + assert_eq!(format!("{}", id), id_str); + } + + #[test] + fn survives_round_trip() { + let id = ChunkId::new(); + let id_str = format!("{}", id); + assert_eq!(id, id_str.parse().unwrap()); + } +} |