From 80bc3be5305fc3a6ed14c1be3e3b3236c5ff88d0 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Fri, 10 May 2024 14:31:49 +0800 Subject: [PATCH 1/2] use base64 to encode/decode raw_metadata --- Cargo.toml | 2 ++ src/index.rs | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 37eb9dd..d461381 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,8 @@ reflink-copy = "0.1.9" serde = "1.0.130" serde_derive = "1.0.130" serde_json = "1.0.68" +base64 = "0.22.0" +base64-serde = "0.7.0" sha1 = "0.10.5" sha2 = "0.10.6" ssri = "9.0.0" diff --git a/src/index.rs b/src/index.rs index b9f5257..f8e4aa1 100644 --- a/src/index.rs +++ b/src/index.rs @@ -18,6 +18,8 @@ use sha2::Sha256; use ssri::Integrity; use walkdir::WalkDir; +use base64_serde::base64_serde_type; + #[cfg(any(feature = "async-std", feature = "tokio"))] use crate::async_lib::{AsyncBufReadExt, AsyncWriteExt}; use crate::content::path::content_path; @@ -50,9 +52,39 @@ struct SerializableMetadata { time: u128, size: usize, metadata: Value, + #[serde(with = "option_base64")] raw_metadata: Option>, } +base64_serde_type!(Base64Standard, base64::engine::general_purpose::STANDARD); + +mod option_base64 { + use super::Base64Standard; + use serde::{Deserialize, Deserializer, Serializer}; + + pub fn serialize(data: &Option>, serializer: S) -> Result + where + S: Serializer, + { + match data { + Some(data) => Base64Standard::serialize(data, serializer), + None => serializer.serialize_none(), + } + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result>, D::Error> + where + D: Deserializer<'de>, + { + // Create a wrapper type to reuse existing "with" attribute easily + #[derive(Deserialize)] + struct WrappedVecU8(#[serde(with = "Base64Standard")] Vec); + + Option::::deserialize(deserializer) + .map(|it| it.map(|wrapped_value| wrapped_value.0)) + } +} + impl PartialEq for SerializableMetadata { fn eq(&self, other: &Self) -> bool { self.key == other.key @@ -586,6 +618,64 @@ mod tests { assert!(!content.exists()); } + #[test] + fn serde_json_raw_metadata() { + let meta = SerializableMetadata { + key: "hello".to_string(), + integrity: Some("sha1-deadbeef".to_string()), + time: 0, + size: 0, + metadata: json!(null), + raw_metadata: Some(vec![b'1', b'2', b'3', b'4']), + }; + + assert_eq!( + serde_json::to_string(&meta).unwrap(), + "{\"key\":\"hello\",\"integrity\":\"sha1-deadbeef\",\"time\":0,\"size\":0,\"metadata\":null,\"raw_metadata\":\"MTIzNA==\"}" + ); + + let value = json!( + { + "key": "hello", + "integrity": "sha1-deadbeef", + "time": 0, + "size": 0, + "metadata": null, + "raw_metadata": "MTIzNA==" + } + ); + + let de_meta: SerializableMetadata = serde_json::from_value(value).unwrap(); + + assert_eq!(de_meta, meta); + } + + #[test] + fn raw_metadata() { + let tmp = tempfile::tempdir().unwrap(); + let dir = tmp.path().to_owned(); + let sri: Integrity = "sha1-deadbeef".parse().unwrap(); + let time = 1_234_567; + let raw_metadata = vec![1, 2, 3, 4]; + let opts = WriteOpts::new() + .integrity(sri.clone()) + .time(time) + .raw_metadata(raw_metadata.clone()); + insert(&dir, "hello", opts).unwrap(); + let entry = find(&dir, "hello").unwrap().unwrap(); + assert_eq!( + entry, + Metadata { + key: String::from("hello"), + integrity: sri, + time: time, + size: 0, + metadata: json!(null), + raw_metadata: Some(raw_metadata), + } + ); + } + #[test] fn round_trip() { let tmp = tempfile::tempdir().unwrap(); From 76a859f2cc850ca031b5f8e13379f2217d16b274 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Sat, 11 May 2024 12:25:08 +0800 Subject: [PATCH 2/2] bump version of `INDEX_VERSION` --- Cargo.toml | 3 +-- src/index.rs | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d461381..d835d94 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,8 +19,7 @@ hex = "0.4.3" memmap2 = { version = "0.5.8", optional = true } miette = "5.7.0" reflink-copy = "0.1.9" -serde = "1.0.130" -serde_derive = "1.0.130" +serde = { version = "1.0.130", features = ["derive"] } serde_json = "1.0.68" base64 = "0.22.0" base64-serde = "0.7.0" diff --git a/src/index.rs b/src/index.rs index f8e4aa1..18db238 100644 --- a/src/index.rs +++ b/src/index.rs @@ -11,7 +11,7 @@ use digest::Digest; use either::{Left, Right}; #[cfg(any(feature = "async-std", feature = "tokio"))] use futures::stream::StreamExt; -use serde_derive::{Deserialize, Serialize}; +use serde::{Deserialize, Serialize}; use serde_json::Value; use sha1::Sha1; use sha2::Sha256; @@ -26,7 +26,7 @@ use crate::content::path::content_path; use crate::errors::{IoErrorExt, Result}; use crate::put::WriteOpts; -const INDEX_VERSION: &str = "5"; +const INDEX_VERSION: &str = "6"; /// Represents a cache index entry, which points to content. #[derive(PartialEq, Debug)]