diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-06-26 06:08:12 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-06-26 06:08:12 +0800 |
| commit | e735671acb3a81e1b7e334e56b9ef3963ba0c2fc (patch) | |
| tree | 46562d6630bb1582b41b6741a7a4f482febf84da /mingling_core/src/renderer | |
| parent | 473cd8e575d03d8bd5439e81cb6835f56a1e964f (diff) | |
feat(core): decouple structured output from Groupped trait
Introduce `StructuralData` sealed trait and `pack_structural!` /
`group_structural!` / `derive(StructuralData)` macros to control
structured rendering separately from grouping. `Groupped` no longer
requires `Serialize`.
Diffstat (limited to 'mingling_core/src/renderer')
| -rw-r--r-- | mingling_core/src/renderer/general.rs | 58 | ||||
| -rw-r--r-- | mingling_core/src/renderer/general/structural_data.rs | 15 |
2 files changed, 50 insertions, 23 deletions
diff --git a/mingling_core/src/renderer/general.rs b/mingling_core/src/renderer/general.rs index 1a9647b..e6da06b 100644 --- a/mingling_core/src/renderer/general.rs +++ b/mingling_core/src/renderer/general.rs @@ -4,13 +4,16 @@ use crate::{ use serde::Serialize; pub mod error; +pub mod structural_data; + +use structural_data::StructuralData; /// A general renderer that supports multiple serialization formats. /// /// The `GeneralRenderer` provides methods to serialize data into various formats /// including JSON, YAML, TOML, and RON, with support for both regular and /// pretty-printed variants. It is designed to work with types that implement -/// the `Serialize` trait. +/// the [`StructuralData`] trait (which implies `Serialize`). pub struct GeneralRenderer; impl GeneralRenderer { @@ -20,7 +23,7 @@ impl GeneralRenderer { /// /// Returns `Err(GeneralRendererSerializeError)` if serialization fails. #[allow(unused_variables)] - pub fn render<T: Serialize + Send>( + pub fn render<T: StructuralData + Send>( data: &T, setting: &GeneralRendererSetting, r: &mut RenderResult, @@ -48,13 +51,13 @@ impl GeneralRenderer { /// /// Returns `Err(GeneralRendererSerializeError)` if serialization fails. #[cfg(feature = "json_serde_fmt")] - pub fn render_to_json<T: Serialize + Send>( + fn render_to_json<T: Serialize + Send>( data: &T, r: &mut RenderResult, ) -> Result<(), GeneralRendererSerializeError> { let json_string = serde_json::to_string(data) .map_err(|e| GeneralRendererSerializeError::new(e.to_string()))?; - r.print(json_string.clone().as_str()); + r.print(&json_string); Ok(()) } @@ -64,13 +67,13 @@ impl GeneralRenderer { /// /// Returns `Err(GeneralRendererSerializeError)` if serialization fails. #[cfg(feature = "json_serde_fmt")] - pub fn render_to_json_pretty<T: Serialize + Send>( + fn render_to_json_pretty<T: Serialize + Send>( data: &T, r: &mut RenderResult, ) -> Result<(), GeneralRendererSerializeError> { let json_string = serde_json::to_string_pretty(data) .map_err(|e| GeneralRendererSerializeError::new(e.to_string()))?; - r.print(json_string.clone().as_str()); + r.print(&json_string); Ok(()) } @@ -80,13 +83,13 @@ impl GeneralRenderer { /// /// Returns `Err(GeneralRendererSerializeError)` if serialization fails. #[cfg(feature = "ron_serde_fmt")] - pub fn render_to_ron<T: Serialize + Send>( + fn render_to_ron<T: Serialize + Send>( data: &T, r: &mut RenderResult, ) -> Result<(), GeneralRendererSerializeError> { let ron_string = ron::ser::to_string(data) .map_err(|e| GeneralRendererSerializeError::new(e.to_string()))?; - r.print(ron_string.to_string().as_str()); + r.print(&ron_string); Ok(()) } @@ -96,17 +99,17 @@ impl GeneralRenderer { /// /// Returns `Err(GeneralRendererSerializeError)` if serialization fails. #[cfg(feature = "ron_serde_fmt")] - pub fn render_to_ron_pretty<T: Serialize + Send>( + fn render_to_ron_pretty<T: Serialize + Send>( data: &T, r: &mut RenderResult, ) -> Result<(), GeneralRendererSerializeError> { - let mut pretty_config = ron::ser::PrettyConfig::new(); - pretty_config.new_line = std::borrow::Cow::from("\n"); - pretty_config.indentor = std::borrow::Cow::from(" "); + let pretty_config = ron::ser::PrettyConfig::new() + .new_line("\n") + .indentor(" "); let ron_string = ron::ser::to_string_pretty(data, pretty_config) .map_err(|e| GeneralRendererSerializeError::new(e.to_string()))?; - r.print(ron_string.to_string().as_str()); + r.print(&ron_string); Ok(()) } @@ -116,13 +119,13 @@ impl GeneralRenderer { /// /// Returns `Err(GeneralRendererSerializeError)` if serialization fails. #[cfg(feature = "toml_serde_fmt")] - pub fn render_to_toml<T: Serialize + Send>( + fn render_to_toml<T: Serialize + Send>( data: &T, r: &mut RenderResult, ) -> Result<(), GeneralRendererSerializeError> { let toml_string = toml::to_string(data).map_err(|e| GeneralRendererSerializeError::new(e.to_string()))?; - r.print(toml_string.to_string().as_str()); + r.print(&toml_string); Ok(()) } @@ -132,13 +135,13 @@ impl GeneralRenderer { /// /// Returns `Err(GeneralRendererSerializeError)` if serialization fails. #[cfg(feature = "yaml_serde_fmt")] - pub fn render_to_yaml<T: Serialize + Send>( + fn render_to_yaml<T: Serialize + Send>( data: &T, r: &mut RenderResult, ) -> Result<(), GeneralRendererSerializeError> { let yaml_string = serde_yaml::to_string(data) .map_err(|e| GeneralRendererSerializeError::new(e.to_string()))?; - r.print(yaml_string.to_string().as_str()); + r.print(&yaml_string); Ok(()) } } @@ -155,6 +158,9 @@ mod tests { value: i32, } + impl crate::__private::StructuralDataSealed for TestData {} + impl StructuralData for TestData {} + fn test_data() -> TestData { TestData { name: "hello".into(), @@ -175,7 +181,8 @@ mod tests { #[test] fn test_render_to_json() { let mut r = RenderResult::default(); - let result = GeneralRenderer::render_to_json(&test_data(), &mut r); + let result = + GeneralRenderer::render(&test_data(), &GeneralRendererSetting::Json, &mut r); assert!(result.is_ok()); assert!(!r.is_empty()); let output: String = r.into(); @@ -189,7 +196,8 @@ mod tests { #[test] fn test_render_to_json_pretty() { let mut r = RenderResult::default(); - let result = GeneralRenderer::render_to_json_pretty(&test_data(), &mut r); + let result = + GeneralRenderer::render(&test_data(), &GeneralRendererSetting::JsonPretty, &mut r); assert!(result.is_ok()); let output: String = r.into(); // Pretty JSON has newlines @@ -200,7 +208,8 @@ mod tests { #[test] fn test_render_to_yaml() { let mut r = RenderResult::default(); - let result = GeneralRenderer::render_to_yaml(&test_data(), &mut r); + let result = + GeneralRenderer::render(&test_data(), &GeneralRendererSetting::Yaml, &mut r); assert!(result.is_ok()); assert!(!r.is_empty()); } @@ -209,7 +218,8 @@ mod tests { #[test] fn test_render_to_toml() { let mut r = RenderResult::default(); - let result = GeneralRenderer::render_to_toml(&test_data(), &mut r); + let result = + GeneralRenderer::render(&test_data(), &GeneralRendererSetting::Toml, &mut r); assert!(result.is_ok()); assert!(!r.is_empty()); } @@ -218,7 +228,8 @@ mod tests { #[test] fn test_render_to_ron() { let mut r = RenderResult::default(); - let result = GeneralRenderer::render_to_ron(&test_data(), &mut r); + let result = + GeneralRenderer::render(&test_data(), &GeneralRendererSetting::Ron, &mut r); assert!(result.is_ok()); assert!(!r.is_empty()); } @@ -227,7 +238,8 @@ mod tests { #[test] fn test_render_to_ron_pretty() { let mut r = RenderResult::default(); - let result = GeneralRenderer::render_to_ron_pretty(&test_data(), &mut r); + let result = + GeneralRenderer::render(&test_data(), &GeneralRendererSetting::RonPretty, &mut r); assert!(result.is_ok()); let output: String = r.into(); assert!(output.contains('\n')); diff --git a/mingling_core/src/renderer/general/structural_data.rs b/mingling_core/src/renderer/general/structural_data.rs new file mode 100644 index 0000000..ac6363e --- /dev/null +++ b/mingling_core/src/renderer/general/structural_data.rs @@ -0,0 +1,15 @@ +use serde::Serialize; + +/// Marker trait for types that support structured output (JSON / YAML / TOML / RON). +/// +/// This trait is a **supertrait** of `serde::Serialize` and is sealed via +/// `__private::StructuralDataSealed`. It can only be implemented through: +/// +/// - `#[derive(StructuralData)]` +/// - `pack_structural!` +/// - `group_structural!` +/// +/// These entry points also register the type in the global `STRUCTURED_TYPES` +/// registry, which is required for the `general_render` match arm to be generated. +#[doc(hidden)] +pub trait StructuralData: Serialize + crate::__private::StructuralDataSealed {} |
