use serde::{ser::SerializeMap, Serialize};
use sha1::Digest;
use sha1::Sha1;
pub struct Manifest {
items: Vec<Item>,
}
impl Default for Manifest {
fn default() -> Self {
Self::new()
}
}
impl Manifest {
#[must_use]
pub fn new() -> Self {
Self { items: Vec::new() }
}
pub fn add_item(&mut self, path: &str, data: &[u8]) {
let checksum = Sha1::digest(data);
let item = Item {
path: path.to_string(),
checksum: format!("{checksum:#x}"),
};
self.items.push(item);
}
pub fn add_items(&mut self, items: &[(&str, &[u8])]) {
for (path, data) in items {
self.add_item(path, data);
}
}
pub fn make_json(&self) -> Result<String, serde_json::Error> {
serde_json::to_string(&self)
}
pub fn clear(&mut self) {
self.items.clear();
}
}
struct Item {
path: String,
checksum: String,
}
impl Serialize for Manifest {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut map = serializer.serialize_map(Some(self.items.len()))?;
for item in &self.items {
map.serialize_entry(&item.path, &item.checksum)?;
}
map.end()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn make_manifest() {
let example_data = "hello world".as_bytes();
let path = "pass.json";
let mut manifest = Manifest::new();
manifest.add_item(path, example_data);
let json = manifest.make_json().unwrap();
let json_expected = r#"{"pass.json":"2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"}"#;
assert_eq!(json_expected, json);
}
#[test]
fn make_manifest_multiple_items() {
let items = vec![
("pass.json", "hello world".as_bytes()),
("logo.png", "PNG DATA 1".as_bytes()),
("background.png", "PNG DATA 2".as_bytes()),
];
let mut manifest = Manifest::new();
manifest.add_items(&items);
let json = manifest.make_json().unwrap();
let json_expected = r#"{"pass.json":"2aae6c35c94fcfb415dbe95f408b9ce91ee846ed","logo.png":"e2507820ce1bd6d09669504e6a5536f7a3ccc94b","background.png":"05cc11980f5826d11c5c1292a4cd04ad11ddbf45"}"#;
assert_eq!(json_expected, json);
}
}