diff --git a/crates/papyrus_config/src/config_test.rs b/crates/papyrus_config/src/config_test.rs index f9bfad1f15..6fa06b6a03 100644 --- a/crates/papyrus_config/src/config_test.rs +++ b/crates/papyrus_config/src/config_test.rs @@ -19,6 +19,7 @@ use crate::converters::deserialize_milliseconds_to_duration; use crate::dumping::{ append_sub_config_name, combine_config_map_and_pointers, + generate_struct_pointer, required_param_description, ser_generated_param, ser_optional_param, @@ -27,6 +28,7 @@ use crate::dumping::{ ser_pointer_target_param, ser_pointer_target_required_param, ser_required_param, + set_pointing_param_paths, SerializeConfig, }; use crate::loading::{ @@ -469,6 +471,92 @@ fn test_replace_pointers() { assert_matches!(err, ConfigError::PointerTargetNotFound { .. }); } +#[test] +fn test_struct_pointers() { + const TARGET_PREFIX: &str = "base"; + let target_value = + RequiredConfig { param_path: "Not a default param_path.".to_owned(), num: 10 }; + let config_map = StructPointersConfig::default().dump(); + + let pointers = generate_struct_pointer( + TARGET_PREFIX.to_owned(), + &target_value, + set_pointing_param_paths(&["a", "b"]), + ); + let stored_map = + combine_config_map_and_pointers(config_map, &pointers, &HashSet::default()).unwrap(); + + // Assert the pointing parameters are correctly set. + assert_eq!( + stored_map["a.param_path"], + json!(SerializedParam { + description: required_param_description("This is param_path.").to_owned(), + content: SerializedContent::PointerTarget( + format!("{TARGET_PREFIX}.param_path").to_owned() + ), + privacy: ParamPrivacy::Public, + }) + ); + assert_eq!( + stored_map["a.num"], + json!(SerializedParam { + description: "This is num.".to_owned(), + content: SerializedContent::PointerTarget(format!("{TARGET_PREFIX}.num").to_owned()), + privacy: ParamPrivacy::Public, + }) + ); + assert_eq!( + stored_map["b.param_path"], + json!(SerializedParam { + description: required_param_description("This is param_path.").to_owned(), + content: SerializedContent::PointerTarget( + format!("{TARGET_PREFIX}.param_path").to_owned() + ), + privacy: ParamPrivacy::Public, + }) + ); + assert_eq!( + stored_map["b.num"], + json!(SerializedParam { + description: "This is num.".to_owned(), + content: SerializedContent::PointerTarget(format!("{TARGET_PREFIX}.num").to_owned()), + privacy: ParamPrivacy::Public, + }) + ); + + // Assert the pointed parameter is correctly set. + assert_eq!( + stored_map[format!("{TARGET_PREFIX}.param_path").to_owned()], + json!(SerializedParam { + description: required_param_description("This is param_path.").to_owned(), + content: SerializedContent::ParamType(SerializationType::String), + privacy: ParamPrivacy::TemporaryValue, + }) + ); + assert_eq!( + stored_map[format!("{TARGET_PREFIX}.num").to_owned()], + json!(SerializedParam { + description: "This is num.".to_owned(), + content: SerializedContent::DefaultValue(json!(10)), + privacy: ParamPrivacy::TemporaryValue, + }) + ); +} + +#[derive(Clone, Default, Serialize, Deserialize, Debug, PartialEq)] +struct StructPointersConfig { + pub a: RequiredConfig, + pub b: RequiredConfig, +} +impl SerializeConfig for StructPointersConfig { + fn dump(&self) -> BTreeMap { + let mut dump = BTreeMap::new(); + dump.append(&mut append_sub_config_name(self.a.dump(), "a")); + dump.append(&mut append_sub_config_name(self.b.dump(), "b")); + dump + } +} + #[derive(Clone, Default, Serialize, Deserialize, Debug, PartialEq)] struct CustomConfig { param_path: String, @@ -565,7 +653,7 @@ fn serialization_precision() { assert_eq!(input, deserialized); } -#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)] +#[derive(Clone, Default, Serialize, Deserialize, Debug, PartialEq)] struct RequiredConfig { param_path: String, num: usize, diff --git a/crates/papyrus_config/src/dumping.rs b/crates/papyrus_config/src/dumping.rs index d47b02a282..5255805be4 100644 --- a/crates/papyrus_config/src/dumping.rs +++ b/crates/papyrus_config/src/dumping.rs @@ -63,6 +63,61 @@ pub type Pointers = HashSet; /// Detailing pointers in the config map. pub type ConfigPointers = Vec<(PointerTarget, Pointers)>; +/// Given a set of paths that are configuration of the same struct type, makes all the paths point +/// to the same target. +pub fn generate_struct_pointer( + target_prefix: ParamPath, + default_instance: &T, + pointer_prefixes: HashSet, +) -> ConfigPointers { + let mut res = ConfigPointers::new(); + for (param_path, serialized_param) in default_instance.dump() { + let pointer_target = to_target(target_prefix.clone(), ¶m_path, &serialized_param); + let pointers = pointer_prefixes + .iter() + .map(|pointer| chain_param_paths(&[pointer, ¶m_path])) + .collect(); + + res.push((pointer_target, pointers)); + } + res +} + +// Converts a serialized param to a pointer target. +fn to_target( + target_prefix: ParamPath, + param_path: &ParamPath, + serialized_param: &SerializedParam, +) -> PointerTarget { + let full_param_path = chain_param_paths(&[&target_prefix, param_path]); + if serialized_param.is_required() { + let description = serialized_param + .description + .strip_prefix(REQUIRED_PARAM_DESCRIPTION_PREFIX) + .unwrap_or(&serialized_param.description) + .trim_start(); + ser_pointer_target_required_param( + &full_param_path, + serialized_param.content.get_serialization_type().unwrap(), + description, + ) + } else { + let default_value = match &serialized_param.content { + SerializedContent::DefaultValue(value) => value, + SerializedContent::PointerTarget(_) => panic!("Pointers to pointer is not supported."), + // We already checked that the param is not required, so it must be a generated param. + SerializedContent::ParamType(_) => { + panic!("Generated pointer targets are not supported.") + } + }; + ser_pointer_target_param(&full_param_path, default_value, &serialized_param.description) + } +} + +fn chain_param_paths(param_paths: &[&str]) -> ParamPath { + param_paths.join(FIELD_SEPARATOR) +} + /// Serialization for configs. pub trait SerializeConfig { /// Conversion of a configuration to a mapping of flattened parameters to their descriptions and diff --git a/crates/papyrus_config/src/lib.rs b/crates/papyrus_config/src/lib.rs index 1507d4f78f..7a383cef54 100644 --- a/crates/papyrus_config/src/lib.rs +++ b/crates/papyrus_config/src/lib.rs @@ -133,7 +133,7 @@ impl SerializedContent { _ => None, }, SerializedContent::PointerTarget(_) => None, - SerializedContent::ParamType(ser_type) => Some(ser_type.clone()), + SerializedContent::ParamType(ser_type) => Some(*ser_type), } } } @@ -158,7 +158,7 @@ impl SerializedParam { } /// A serialized type of a configuration parameter. -#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, strum_macros::Display)] +#[derive(Clone, Copy, Serialize, Deserialize, Debug, PartialEq, strum_macros::Display)] #[allow(missing_docs)] pub enum SerializationType { Boolean,