From e87f2a2b3a5912387d89ef1229d4826b557bb8dc Mon Sep 17 00:00:00 2001 From: Peter Kolloch Date: Sat, 17 Feb 2024 13:55:13 +0700 Subject: feat(tvix/nix-compat): serde for StorePath[Ref]s Necessary, if we want to use it inside of `Derivation` etc. Change-Id: I8888060417b2ee83ac52d7ec3e7b27c393271d8b Reviewed-on: https://cl.tvl.fyi/c/depot/+/10947 Reviewed-by: tazjin Autosubmit: Peter Kolloch Tested-by: BuildkiteCI Reviewed-by: flokli --- tvix/nix-compat/src/store_path/mod.rs | 94 +++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) (limited to 'tvix/nix-compat/src') diff --git a/tvix/nix-compat/src/store_path/mod.rs b/tvix/nix-compat/src/store_path/mod.rs index e23002bfb97e..ecf8ec8fa653 100644 --- a/tvix/nix-compat/src/store_path/mod.rs +++ b/tvix/nix-compat/src/store_path/mod.rs @@ -1,5 +1,6 @@ use crate::nixbase32; use data_encoding::{DecodeError, BASE64}; +use serde::{Deserialize, Serialize}; use std::{ fmt, path::PathBuf, @@ -135,6 +136,26 @@ impl StorePath { } } +impl<'de> Deserialize<'de> for StorePath { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let r = as Deserialize<'de>>::deserialize(deserializer)?; + Ok(r.to_owned()) + } +} + +impl Serialize for StorePath { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let r: StorePathRef = self.into(); + r.serialize(serializer) + } +} + /// Like [StorePath], but without a heap allocation for the name. /// Used by [StorePath] for parsing. /// @@ -220,6 +241,35 @@ impl<'a> StorePathRef<'a> { } } +impl<'de> Deserialize<'de> for StorePathRef<'de> { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let string: &'de str = Deserialize::deserialize(deserializer)?; + let stripped: Option<&str> = string.strip_prefix(STORE_DIR_WITH_SLASH); + let stripped: &str = stripped.ok_or_else(|| { + serde::de::Error::invalid_value( + serde::de::Unexpected::Str(string), + &"store path prefix", + ) + })?; + StorePathRef::from_bytes(stripped.as_bytes()).map_err(|_| { + serde::de::Error::invalid_value(serde::de::Unexpected::Str(string), &"StorePath") + }) + } +} + +impl Serialize for StorePathRef<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let string: String = self.to_absolute_path(); + string.serialize(serializer) + } +} + /// NAME_CHARS contains `true` for bytes that are valid in store path names, /// not accounting for '.' being permitted only past the first character. static NAME_CHARS: [bool; 256] = { @@ -388,6 +438,50 @@ mod tests { ); } + #[test] + fn serialize_ref() { + let store_path_str = + "/nix/store/00bgd045z0d4icpbc2yyz4gx48ak44la-net-tools-1.60_p20170221182432"; + let nixpath_actual = + StorePathRef::from_absolute_path(store_path_str.as_bytes()).expect("can parse"); + + let serialized = serde_json::to_string(&nixpath_actual).expect("can serialize"); + + assert_eq!( + "\"/nix/store/00bgd045z0d4icpbc2yyz4gx48ak44la-net-tools-1.60_p20170221182432\"", + &serialized + ); + } + + #[test] + fn serialize_owned() { + let store_path_str = + "/nix/store/00bgd045z0d4icpbc2yyz4gx48ak44la-net-tools-1.60_p20170221182432"; + let nixpath_actual = StorePathRef::from_absolute_path(store_path_str.as_bytes()) + .expect("can parse") + .to_owned(); + + let serialized = serde_json::to_string(&nixpath_actual).expect("can serialize"); + + assert_eq!( + "\"/nix/store/00bgd045z0d4icpbc2yyz4gx48ak44la-net-tools-1.60_p20170221182432\"", + &serialized + ); + } + + #[test] + fn deserialize_ref() { + let store_path_str_json = + "\"/nix/store/00bgd045z0d4icpbc2yyz4gx48ak44la-net-tools-1.60_p20170221182432\""; + + let store_path: StorePath = serde_json::from_str(store_path_str_json).expect("valid json"); + + assert_eq!( + "/nix/store/00bgd045z0d4icpbc2yyz4gx48ak44la-net-tools-1.60_p20170221182432", + store_path.to_absolute_path() + ); + } + #[test_case( "/nix/store/00bgd045z0d4icpbc2yyz4gx48ak44la-net-tools-1.60_p20170221182432", (StorePath::from_bytes(b"00bgd045z0d4icpbc2yyz4gx48ak44la-net-tools-1.60_p20170221182432").unwrap(), PathBuf::new()) -- cgit 1.4.1