summaryrefslogtreecommitdiff
path: root/src/chunkmeta.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/chunkmeta.rs')
-rw-r--r--src/chunkmeta.rs114
1 files changed, 51 insertions, 63 deletions
diff --git a/src/chunkmeta.rs b/src/chunkmeta.rs
index 37e2ed5..e2fa9b3 100644
--- a/src/chunkmeta.rs
+++ b/src/chunkmeta.rs
@@ -1,28 +1,21 @@
+//! Metadata about a chunk.
+
+use crate::label::Label;
use serde::{Deserialize, Serialize};
use std::default::Default;
use std::str::FromStr;
/// Metadata about chunks.
///
-/// We manage three bits of metadata about chunks, in addition to its
-/// identifier:
-///
-/// * for all chunks, a [SHA256][] checksum of the chunk content
-///
-/// * for generation chunks, an indication that it is a generation
-/// chunk, and a timestamp for when making the generation snapshot
-/// ended
-///
-/// There is no syntax or semantics imposed on the timestamp, but a
-/// client should probably use [ISO 8601][] representation.
+/// We a single piece of metadata about chunks, in addition to its
+/// identifier: a label assigned by the client. Currently, this is a
+/// [SHA256][] checksum of the chunk content.
///
/// For HTTP, the metadata will be serialised as a JSON object, like this:
///
/// ~~~json
/// {
-/// "sha256": "09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b",
-/// "generation": true,
-/// "ended": "2020-09-17T08:17:13+03:00"
+/// "label": "09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b",
/// }
/// ~~~
///
@@ -35,55 +28,44 @@ use std::str::FromStr;
///
/// [ISO 8601]: https://en.wikipedia.org/wiki/ISO_8601
/// [SHA256]: https://en.wikipedia.org/wiki/SHA-2
-#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
+#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
pub struct ChunkMeta {
- sha256: String,
- // The remaining fields are Options so that JSON parsing doesn't
- // insist on them being there in the textual representation.
- generation: Option<bool>,
- ended: Option<String>,
+ label: String,
}
impl ChunkMeta {
/// Create a new data chunk.
///
/// Data chunks are not for generations.
- pub fn new(sha256: &str) -> Self {
+ pub fn new(label: &Label) -> Self {
ChunkMeta {
- sha256: sha256.to_string(),
- generation: None,
- ended: None,
+ label: label.serialize(),
}
}
- /// Create a new generation chunk.
- pub fn new_generation(sha256: &str, ended: &str) -> Self {
- ChunkMeta {
- sha256: sha256.to_string(),
- generation: Some(true),
- ended: Some(ended.to_string()),
- }
- }
-
- /// Is this a generation chunk?
- pub fn is_generation(&self) -> bool {
- matches!(self.generation, Some(true))
- }
-
- /// When did this generation end?
- pub fn ended(&self) -> Option<&str> {
- self.ended.as_deref()
+ /// The label of the content of the chunk.
+ ///
+ /// The caller should not interpret the label in any way. It
+ /// happens to be a SHA256 of the cleartext contents of the
+ /// checksum for now, but that _will_ change in the future.
+ pub fn label(&self) -> &str {
+ &self.label
}
- /// SHA256 checksum of the content of the chunk.
- pub fn sha256(&self) -> &str {
- &self.sha256
+ /// Serialize from a textual JSON representation.
+ pub fn from_json(json: &str) -> Result<Self, serde_json::Error> {
+ serde_json::from_str(json)
}
/// Serialize as JSON.
pub fn to_json(&self) -> String {
serde_json::to_string(self).unwrap()
}
+
+ /// Serialize as JSON, as a byte vector.
+ pub fn to_json_vec(&self) -> Vec<u8> {
+ self.to_json().as_bytes().to_vec()
+ }
}
impl FromStr for ChunkMeta {
@@ -97,48 +79,54 @@ impl FromStr for ChunkMeta {
#[cfg(test)]
mod test {
- use super::ChunkMeta;
+ use super::{ChunkMeta, Label};
#[test]
fn new_creates_data_chunk() {
- let meta = ChunkMeta::new("abcdef");
- assert!(!meta.is_generation());
- assert_eq!(meta.ended(), None);
- assert_eq!(meta.sha256(), "abcdef");
+ let sum = Label::sha256(b"abcdef");
+ let meta = ChunkMeta::new(&sum);
+ assert_eq!(meta.label(), sum.serialize());
}
#[test]
fn new_generation_creates_generation_chunk() {
- let meta = ChunkMeta::new_generation("abcdef", "2020-09-17T08:17:13+03:00");
- assert!(meta.is_generation());
- assert_eq!(meta.ended(), Some("2020-09-17T08:17:13+03:00"));
- assert_eq!(meta.sha256(), "abcdef");
+ let sum = Label::sha256(b"abcdef");
+ let meta = ChunkMeta::new(&sum);
+ assert_eq!(meta.label(), sum.serialize());
}
#[test]
fn data_chunk_from_json() {
- let meta: ChunkMeta = r#"{"sha256": "abcdef"}"#.parse().unwrap();
- assert!(!meta.is_generation());
- assert_eq!(meta.ended(), None);
- assert_eq!(meta.sha256(), "abcdef");
+ let meta: ChunkMeta = r#"{"label": "abcdef"}"#.parse().unwrap();
+ assert_eq!(meta.label(), "abcdef");
}
#[test]
fn generation_chunk_from_json() {
let meta: ChunkMeta =
- r#"{"sha256": "abcdef", "generation": true, "ended": "2020-09-17T08:17:13+03:00"}"#
+ r#"{"label": "abcdef", "generation": true, "ended": "2020-09-17T08:17:13+03:00"}"#
.parse()
.unwrap();
- assert!(meta.is_generation());
- assert_eq!(meta.ended(), Some("2020-09-17T08:17:13+03:00"));
- assert_eq!(meta.sha256(), "abcdef");
+
+ assert_eq!(meta.label(), "abcdef");
}
#[test]
- fn json_roundtrip() {
- let meta = ChunkMeta::new_generation("abcdef", "2020-09-17T08:17:13+03:00");
+ fn generation_json_roundtrip() {
+ let sum = Label::sha256(b"abcdef");
+ let meta = ChunkMeta::new(&sum);
let json = serde_json::to_string(&meta).unwrap();
let meta2 = serde_json::from_str(&json).unwrap();
assert_eq!(meta, meta2);
}
+
+ #[test]
+ fn data_json_roundtrip() {
+ let sum = Label::sha256(b"abcdef");
+ let meta = ChunkMeta::new(&sum);
+ let json = meta.to_json_vec();
+ let meta2 = serde_json::from_slice(&json).unwrap();
+ assert_eq!(meta, meta2);
+ assert_eq!(meta.to_json_vec(), meta2.to_json_vec());
+ }
}