From d1a74ce57e5be72436376a829e9c7e1e7c1c561b Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Fri, 26 Jun 2026 06:27:16 +0800 Subject: refactor(general_renderer): rename to structural_renderer --- mingling_core/src/any.rs | 12 +- mingling_core/src/any/group.rs | 2 +- mingling_core/src/comp/flags.rs | 2 +- mingling_core/src/comp/shell_ctx.rs | 2 +- mingling_core/src/comp/suggest.rs | 4 +- mingling_core/src/lib.rs | 14 +- mingling_core/src/program.rs | 8 +- mingling_core/src/program/collection.rs | 16 +- mingling_core/src/program/collection/mock.rs | 16 +- mingling_core/src/program/config.rs | 116 ++++----- mingling_core/src/program/exec.rs | 18 +- mingling_core/src/program/hook.rs | 10 +- mingling_core/src/renderer.rs | 4 +- mingling_core/src/renderer/general.rs | 268 --------------------- mingling_core/src/renderer/general/error.rs | 68 ------ .../src/renderer/general/structural_data.rs | 15 -- mingling_core/src/renderer/structural.rs | 268 +++++++++++++++++++++ mingling_core/src/renderer/structural/error.rs | 68 ++++++ .../src/renderer/structural/structural_data.rs | 15 ++ 19 files changed, 463 insertions(+), 463 deletions(-) delete mode 100644 mingling_core/src/renderer/general.rs delete mode 100644 mingling_core/src/renderer/general/error.rs delete mode 100644 mingling_core/src/renderer/general/structural_data.rs create mode 100644 mingling_core/src/renderer/structural.rs create mode 100644 mingling_core/src/renderer/structural/error.rs create mode 100644 mingling_core/src/renderer/structural/structural_data.rs (limited to 'mingling_core/src') diff --git a/mingling_core/src/any.rs b/mingling_core/src/any.rs index ef9f912..ad02b0c 100644 --- a/mingling_core/src/any.rs +++ b/mingling_core/src/any.rs @@ -161,7 +161,7 @@ mod tests { } #[derive(Debug, Clone, PartialEq)] - #[cfg_attr(feature = "general_renderer", derive(serde::Serialize))] + #[cfg_attr(feature = "structural_renderer", derive(serde::Serialize))] struct AlphaData { value: i32, } @@ -173,7 +173,7 @@ mod tests { } #[derive(Debug, Clone, PartialEq)] - #[cfg_attr(feature = "general_renderer", derive(serde::Serialize))] + #[cfg_attr(feature = "structural_renderer", derive(serde::Serialize))] struct BetaData { name: String, } @@ -186,7 +186,7 @@ mod tests { #[derive(Debug, Clone, PartialEq)] #[allow(dead_code)] - #[cfg_attr(feature = "general_renderer", derive(serde::Serialize))] + #[cfg_attr(feature = "structural_renderer", derive(serde::Serialize))] struct GammaData; impl Groupped for GammaData { @@ -333,9 +333,9 @@ mod tests { assert_eq!(format!("{}", NextProcess::Renderer), "Renderer"); } - // AnyOutput::restore general_renderer feature only + // AnyOutput::restore structural_renderer feature only - #[cfg(feature = "general_renderer")] + #[cfg(feature = "structural_renderer")] #[test] fn test_any_output_restore_success() { use serde::Serialize; @@ -357,7 +357,7 @@ mod tests { assert_eq!(restored, Some(SerData { x: 42 })); } - #[cfg(feature = "general_renderer")] + #[cfg(feature = "structural_renderer")] #[test] fn test_any_output_restore_type_mismatch() { use serde::Serialize; diff --git a/mingling_core/src/any/group.rs b/mingling_core/src/any/group.rs index 07f8400..afe5e3a 100644 --- a/mingling_core/src/any/group.rs +++ b/mingling_core/src/any/group.rs @@ -3,7 +3,7 @@ use crate::{AnyOutput, ChainProcess}; /// Used to mark a type with a unique enum ID, assisting dynamic dispatch /// /// **Note:** Unlike earlier versions, `Groupped` no longer requires `Serialize` -/// even when the `general_renderer` feature is enabled. Structured output is +/// even when the `structural_renderer` feature is enabled. Structured output is /// controlled separately via the [`StructalData`] trait. pub trait Groupped where diff --git a/mingling_core/src/comp/flags.rs b/mingling_core/src/comp/flags.rs index 424fe8b..9a88d2e 100644 --- a/mingling_core/src/comp/flags.rs +++ b/mingling_core/src/comp/flags.rs @@ -5,7 +5,7 @@ use just_fmt::snake_case; /// This enum defines the supported shell types that can be used for /// generating shell-specific command syntax, scripts, or completions. #[derive(Default, Debug, Clone)] -#[cfg_attr(feature = "general_renderer", derive(serde::Serialize))] +#[cfg_attr(feature = "structural_renderer", derive(serde::Serialize))] pub enum ShellFlag { /// Represents the Bash shell. #[default] diff --git a/mingling_core/src/comp/shell_ctx.rs b/mingling_core/src/comp/shell_ctx.rs index 616eade..cfa4700 100644 --- a/mingling_core/src/comp/shell_ctx.rs +++ b/mingling_core/src/comp/shell_ctx.rs @@ -6,7 +6,7 @@ use crate::{Flag, ShellFlag, Suggest}; /// providing information about the current command line state /// to guide how completions should be generated. #[derive(Default, Debug)] -#[cfg_attr(feature = "general_renderer", derive(serde::Serialize))] +#[cfg_attr(feature = "structural_renderer", derive(serde::Serialize))] pub struct ShellContext { /// The full command line (-f / --command-line) pub command_line: String, diff --git a/mingling_core/src/comp/suggest.rs b/mingling_core/src/comp/suggest.rs index bd5dea6..a81de64 100644 --- a/mingling_core/src/comp/suggest.rs +++ b/mingling_core/src/comp/suggest.rs @@ -5,7 +5,7 @@ use crate::ShellContext; /// A completion suggestion that tells the shell how to perform completion. /// This can be either a set of specific suggestion items or a request for file completion. #[derive(Debug, Default, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "general_renderer", derive(serde::Serialize))] +#[cfg_attr(feature = "structural_renderer", derive(serde::Serialize))] pub enum Suggest { /// A set of specific suggestion items for the shell to display. Suggest(BTreeSet), @@ -78,7 +78,7 @@ impl std::ops::DerefMut for Suggest { /// The first `String` always holds the suggestion text, and the second `String` (if present) /// holds an optional description providing additional context. #[derive(Debug, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "general_renderer", derive(serde::Serialize))] +#[cfg_attr(feature = "structural_renderer", derive(serde::Serialize))] pub enum SuggestItem { /// A simple suggestion with only the suggestion text. Simple(String), diff --git a/mingling_core/src/lib.rs b/mingling_core/src/lib.rs index 9d0ac2a..ef7d192 100644 --- a/mingling_core/src/lib.rs +++ b/mingling_core/src/lib.rs @@ -19,12 +19,12 @@ pub mod test { pub use crate::tester::*; } -#[cfg(feature = "general_renderer")] -pub use crate::renderer::general::GeneralRenderer; +#[cfg(feature = "structural_renderer")] +pub use crate::renderer::structural::StructuralRenderer; // NOT re-exported at top level: the `StructuralData` trait is sealed and only // accessible through the derive macro. Users who need the trait can access it -// via `mingling::renderer::general::StructuralData` (through the inner alias). +// via `mingling::renderer::structural::StructuralData` (through the inner alias). pub use crate::any::group::*; pub use crate::any::*; @@ -42,8 +42,8 @@ pub mod error { pub use crate::asset::chain::error::*; pub use crate::exec::error::*; pub use crate::program::error::*; - #[cfg(feature = "general_renderer")] - pub use crate::renderer::general::error::*; + #[cfg(feature = "structural_renderer")] + pub use crate::renderer::structural::error::*; } pub use crate::program::*; @@ -83,8 +83,8 @@ pub mod __private { /// Re-export so the derive macro can reference the trait without /// conflicting with the derive macro name at `::mingling::StructuralData`. - #[cfg(feature = "general_renderer")] - pub use crate::renderer::general::structural_data::StructuralData; + #[cfg(feature = "structural_renderer")] + pub use crate::renderer::structural::structural_data::StructuralData; } #[doc(hidden)] diff --git a/mingling_core/src/program.rs b/mingling_core/src/program.rs index e791d86..71d5290 100644 --- a/mingling_core/src/program.rs +++ b/mingling_core/src/program.rs @@ -56,8 +56,8 @@ where pub stdout_setting: ProgramStdoutSetting, pub user_context: ProgramUserContext, - #[cfg(feature = "general_renderer")] - pub general_renderer_name: GeneralRendererSetting, + #[cfg(feature = "structural_renderer")] + pub structural_renderer_name: StructuralRendererSetting, pub(crate) hooks: Vec>, @@ -99,8 +99,8 @@ where stdout_setting: ProgramStdoutSetting::default(), user_context: ProgramUserContext::default(), - #[cfg(feature = "general_renderer")] - general_renderer_name: GeneralRendererSetting::Disable, + #[cfg(feature = "structural_renderer")] + structural_renderer_name: StructuralRendererSetting::Disable, hooks: Vec::new(), diff --git a/mingling_core/src/program/collection.rs b/mingling_core/src/program/collection.rs index 36a0c94..044379c 100644 --- a/mingling_core/src/program/collection.rs +++ b/mingling_core/src/program/collection.rs @@ -6,8 +6,8 @@ use crate::Dispatcher; use crate::{AnyOutput, ChainProcess, Groupped, RenderResult}; -#[cfg(feature = "general_renderer")] -use crate::{GeneralRendererSetting, error::GeneralRendererSerializeError}; +#[cfg(feature = "structural_renderer")] +use crate::{StructuralRendererSetting, error::StructuralRendererSerializeError}; #[cfg(feature = "comp")] use crate::{ShellContext, Suggest}; @@ -78,15 +78,15 @@ pub trait ProgramCollect { /// Whether the program has a chain that can handle the current [`AnyOutput`](./struct.AnyOutput.html) fn has_chain(any: &AnyOutput) -> bool; - /// Perform general rendering and presentation of any type + /// Perform structural rendering and presentation of any type /// /// # Errors /// - /// Returns `Err(GeneralRendererSerializeError)` if serialization of the + /// Returns `Err(StructuralRendererSerializeError)` if serialization of the /// output value fails. - #[cfg(feature = "general_renderer")] - fn general_render( + #[cfg(feature = "structural_renderer")] + fn structural_render( any: AnyOutput, - setting: &GeneralRendererSetting, - ) -> Result; + setting: &StructuralRendererSetting, + ) -> Result; } diff --git a/mingling_core/src/program/collection/mock.rs b/mingling_core/src/program/collection/mock.rs index caef804..b37a709 100644 --- a/mingling_core/src/program/collection/mock.rs +++ b/mingling_core/src/program/collection/mock.rs @@ -6,16 +6,16 @@ use crate::Dispatcher; use crate::{AnyOutput, ChainProcess, Groupped, ProgramCollect, RenderResult}; -#[cfg(feature = "general_renderer")] -use crate::{GeneralRendererSetting, error::GeneralRendererSerializeError}; +#[cfg(feature = "structural_renderer")] +use crate::{StructuralRendererSetting, error::StructuralRendererSerializeError}; #[cfg(feature = "comp")] use crate::{ShellContext, Suggest}; -#[cfg(feature = "general_renderer")] +#[cfg(feature = "structural_renderer")] use serde::Serialize; -#[cfg_attr(feature = "general_renderer", derive(Serialize))] +#[cfg_attr(feature = "structural_renderer", derive(Serialize))] #[allow(unused)] pub enum MockProgramCollect { Foo, @@ -91,11 +91,11 @@ impl ProgramCollect for MockProgramCollect { unreachable!() } - #[cfg(feature = "general_renderer")] - fn general_render( + #[cfg(feature = "structural_renderer")] + fn structural_render( _any: AnyOutput, - _setting: &GeneralRendererSetting, - ) -> Result { + _setting: &StructuralRendererSetting, + ) -> Result { unreachable!() } } diff --git a/mingling_core/src/program/config.rs b/mingling_core/src/program/config.rs index 4e193f2..6d54a4e 100644 --- a/mingling_core/src/program/config.rs +++ b/mingling_core/src/program/config.rs @@ -119,12 +119,12 @@ impl Default for ProgramUserContext { } } -#[cfg(feature = "general_renderer")] +#[cfg(feature = "structural_renderer")] #[derive(Debug, Clone, Default)] -/// Settings for the general renderer output format. +/// Settings for the structural renderer output format. /// /// Controls how structured data (e.g., JSON, YAML, TOML) is rendered to stdout. -pub enum GeneralRendererSetting { +pub enum StructuralRendererSetting { /// Do not render structured output (use default formatting). #[default] Disable, @@ -148,61 +148,61 @@ pub enum GeneralRendererSetting { RonPretty, } -#[cfg(feature = "general_renderer")] -impl std::str::FromStr for GeneralRendererSetting { +#[cfg(feature = "structural_renderer")] +impl std::str::FromStr for StructuralRendererSetting { type Err = String; fn from_str(s: &str) -> Result { match just_fmt::kebab_case!(s).as_str() { - "disable" => Ok(GeneralRendererSetting::Disable), + "disable" => Ok(StructuralRendererSetting::Disable), #[cfg(feature = "json_serde_fmt")] - "json" => Ok(GeneralRendererSetting::Json), + "json" => Ok(StructuralRendererSetting::Json), #[cfg(feature = "json_serde_fmt")] - "json-pretty" => Ok(GeneralRendererSetting::JsonPretty), + "json-pretty" => Ok(StructuralRendererSetting::JsonPretty), #[cfg(feature = "yaml_serde_fmt")] - "yaml" => Ok(GeneralRendererSetting::Yaml), + "yaml" => Ok(StructuralRendererSetting::Yaml), #[cfg(feature = "toml_serde_fmt")] - "toml" => Ok(GeneralRendererSetting::Toml), + "toml" => Ok(StructuralRendererSetting::Toml), #[cfg(feature = "ron_serde_fmt")] - "ron" => Ok(GeneralRendererSetting::Ron), + "ron" => Ok(StructuralRendererSetting::Ron), #[cfg(feature = "ron_serde_fmt")] - "ron-pretty" => Ok(GeneralRendererSetting::RonPretty), + "ron-pretty" => Ok(StructuralRendererSetting::RonPretty), _ => Err(format!("Invalid renderer: '{s}'")), } } } -#[cfg(feature = "general_renderer")] -impl From<&str> for GeneralRendererSetting { +#[cfg(feature = "structural_renderer")] +impl From<&str> for StructuralRendererSetting { fn from(s: &str) -> Self { - s.parse().unwrap_or(GeneralRendererSetting::Disable) + s.parse().unwrap_or(StructuralRendererSetting::Disable) } } -#[cfg(feature = "general_renderer")] -impl From for GeneralRendererSetting { +#[cfg(feature = "structural_renderer")] +impl From for StructuralRendererSetting { fn from(s: String) -> Self { s.as_str().into() } } -#[cfg(feature = "general_renderer")] -impl std::fmt::Display for GeneralRendererSetting { +#[cfg(feature = "structural_renderer")] +impl std::fmt::Display for StructuralRendererSetting { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - GeneralRendererSetting::Disable => write!(f, "disable"), + StructuralRendererSetting::Disable => write!(f, "disable"), #[cfg(feature = "json_serde_fmt")] - GeneralRendererSetting::Json => write!(f, "json"), + StructuralRendererSetting::Json => write!(f, "json"), #[cfg(feature = "json_serde_fmt")] - GeneralRendererSetting::JsonPretty => write!(f, "json-pretty"), + StructuralRendererSetting::JsonPretty => write!(f, "json-pretty"), #[cfg(feature = "yaml_serde_fmt")] - GeneralRendererSetting::Yaml => write!(f, "yaml"), + StructuralRendererSetting::Yaml => write!(f, "yaml"), #[cfg(feature = "toml_serde_fmt")] - GeneralRendererSetting::Toml => write!(f, "toml"), + StructuralRendererSetting::Toml => write!(f, "toml"), #[cfg(feature = "ron_serde_fmt")] - GeneralRendererSetting::Ron => write!(f, "ron"), + StructuralRendererSetting::Ron => write!(f, "ron"), #[cfg(feature = "ron_serde_fmt")] - GeneralRendererSetting::RonPretty => write!(f, "ron-pretty"), + StructuralRendererSetting::RonPretty => write!(f, "ron-pretty"), } } } @@ -236,113 +236,113 @@ mod tests { assert!(!ctx.assume_yes); } - #[cfg(feature = "general_renderer")] - mod general_renderer_tests { + #[cfg(feature = "structural_renderer")] + mod structural_renderer_tests { use super::*; #[test] fn from_str_disable() { - let val: GeneralRendererSetting = "disable".parse().unwrap(); - assert!(matches!(val, GeneralRendererSetting::Disable)); + let val: StructuralRendererSetting = "disable".parse().unwrap(); + assert!(matches!(val, StructuralRendererSetting::Disable)); } #[cfg(feature = "json_serde_fmt")] #[test] fn from_str_json() { - let val: GeneralRendererSetting = "json".parse().unwrap(); - assert!(matches!(val, GeneralRendererSetting::Json)); + let val: StructuralRendererSetting = "json".parse().unwrap(); + assert!(matches!(val, StructuralRendererSetting::Json)); } #[cfg(feature = "json_serde_fmt")] #[test] fn from_str_json_pretty() { - let val: GeneralRendererSetting = "json-pretty".parse().unwrap(); - assert!(matches!(val, GeneralRendererSetting::JsonPretty)); + let val: StructuralRendererSetting = "json-pretty".parse().unwrap(); + assert!(matches!(val, StructuralRendererSetting::JsonPretty)); } #[cfg(feature = "yaml_serde_fmt")] #[test] fn from_str_yaml() { - let val: GeneralRendererSetting = "yaml".parse().unwrap(); - assert!(matches!(val, GeneralRendererSetting::Yaml)); + let val: StructuralRendererSetting = "yaml".parse().unwrap(); + assert!(matches!(val, StructuralRendererSetting::Yaml)); } #[cfg(feature = "toml_serde_fmt")] #[test] fn from_str_toml() { - let val: GeneralRendererSetting = "toml".parse().unwrap(); - assert!(matches!(val, GeneralRendererSetting::Toml)); + let val: StructuralRendererSetting = "toml".parse().unwrap(); + assert!(matches!(val, StructuralRendererSetting::Toml)); } #[cfg(feature = "ron_serde_fmt")] #[test] fn from_str_ron() { - let val: GeneralRendererSetting = "ron".parse().unwrap(); - assert!(matches!(val, GeneralRendererSetting::Ron)); + let val: StructuralRendererSetting = "ron".parse().unwrap(); + assert!(matches!(val, StructuralRendererSetting::Ron)); } #[cfg(feature = "ron_serde_fmt")] #[test] fn from_str_ron_pretty() { - let val: GeneralRendererSetting = "ron-pretty".parse().unwrap(); - assert!(matches!(val, GeneralRendererSetting::RonPretty)); + let val: StructuralRendererSetting = "ron-pretty".parse().unwrap(); + assert!(matches!(val, StructuralRendererSetting::RonPretty)); } #[test] fn from_str_invalid() { - let res: Result = "invalid".parse(); + let res: Result = "invalid".parse(); assert!(res.is_err()); } #[test] fn from_str_kebab_case() { - let val: GeneralRendererSetting = "JsonPretty".parse().unwrap(); - assert!(matches!(val, GeneralRendererSetting::JsonPretty)); + let val: StructuralRendererSetting = "JsonPretty".parse().unwrap(); + assert!(matches!(val, StructuralRendererSetting::JsonPretty)); } #[test] fn from_str_case_insensitive() { - let val: GeneralRendererSetting = "JSON".parse().unwrap(); - assert!(matches!(val, GeneralRendererSetting::Json)); + let val: StructuralRendererSetting = "JSON".parse().unwrap(); + assert!(matches!(val, StructuralRendererSetting::Json)); } #[test] fn from_and_str() { - let val = >::from("json"); + let val = >::from("json"); assert!( - matches!(val, GeneralRendererSetting::Disable) - || matches!(val, GeneralRendererSetting::Json) + matches!(val, StructuralRendererSetting::Disable) + || matches!(val, StructuralRendererSetting::Json) ); - let val = >::from("invalid"); - assert!(matches!(val, GeneralRendererSetting::Disable)); + let val = >::from("invalid"); + assert!(matches!(val, StructuralRendererSetting::Disable)); } #[test] fn from_string() { - let val = >::from("json-pretty".to_string()); + let val = >::from("json-pretty".to_string()); assert!( - matches!(val, GeneralRendererSetting::Disable) - || matches!(val, GeneralRendererSetting::JsonPretty) + matches!(val, StructuralRendererSetting::Disable) + || matches!(val, StructuralRendererSetting::JsonPretty) ); } #[test] fn display_disable() { - assert_eq!(GeneralRendererSetting::Disable.to_string(), "disable"); + assert_eq!(StructuralRendererSetting::Disable.to_string(), "disable"); } #[cfg(feature = "json_serde_fmt")] #[test] fn display_json() { - assert_eq!(GeneralRendererSetting::Json.to_string(), "json"); + assert_eq!(StructuralRendererSetting::Json.to_string(), "json"); } #[cfg(feature = "json_serde_fmt")] #[test] fn display_json_pretty() { assert_eq!( - GeneralRendererSetting::JsonPretty.to_string(), + StructuralRendererSetting::JsonPretty.to_string(), "json-pretty" ); } diff --git a/mingling_core/src/program/exec.rs b/mingling_core/src/program/exec.rs index 1832430..d1983ed 100644 --- a/mingling_core/src/program/exec.rs +++ b/mingling_core/src/program/exec.rs @@ -459,22 +459,22 @@ pub(crate) fn handle_program_control>( #[inline] #[allow(unused_variables)] fn render>(program: &Program, any: AnyOutput) -> RenderResult { - #[cfg(not(feature = "general_renderer"))] + #[cfg(not(feature = "structural_renderer"))] { let mut render_result = RenderResult::default(); C::render(any, &mut render_result); render_result } - #[cfg(feature = "general_renderer")] + #[cfg(feature = "structural_renderer")] { #[allow(unreachable_patterns)] - match program.general_renderer_name { - super::GeneralRendererSetting::Disable => { + match program.structural_renderer_name { + super::StructuralRendererSetting::Disable => { let mut render_result = RenderResult::default(); C::render(any, &mut render_result); render_result } - _ => C::general_render(any, &program.general_renderer_name).unwrap(), + _ => C::structural_render(any, &program.structural_renderer_name).unwrap(), } } } @@ -485,17 +485,17 @@ fn render_help>( program: &Program, entry: AnyOutput, ) -> RenderResult { - #[cfg(not(feature = "general_renderer"))] + #[cfg(not(feature = "structural_renderer"))] { let mut render_result = RenderResult::default(); C::render_help(entry, &mut render_result); render_result } - #[cfg(feature = "general_renderer")] + #[cfg(feature = "structural_renderer")] { #[allow(unreachable_patterns)] - match program.general_renderer_name { - super::GeneralRendererSetting::Disable => { + match program.structural_renderer_name { + super::StructuralRendererSetting::Disable => { let mut render_result = RenderResult::default(); C::render_help(entry, &mut render_result); render_result diff --git a/mingling_core/src/program/hook.rs b/mingling_core/src/program/hook.rs index 7b07d90..cd758ca 100644 --- a/mingling_core/src/program/hook.rs +++ b/mingling_core/src/program/hook.rs @@ -637,7 +637,7 @@ mod tests { use std::sync::atomic::{AtomicBool, Ordering}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] - #[cfg_attr(feature = "general_renderer", derive(serde::Serialize))] + #[cfg_attr(feature = "structural_renderer", derive(serde::Serialize))] enum MockHookEnum { A, B, @@ -701,11 +701,11 @@ mod tests { unreachable!() } - #[cfg(feature = "general_renderer")] - fn general_render( + #[cfg(feature = "structural_renderer")] + fn structural_render( _any: crate::AnyOutput, - _setting: &crate::GeneralRendererSetting, - ) -> Result { + _setting: &crate::StructuralRendererSetting, + ) -> Result { unreachable!() } } diff --git a/mingling_core/src/renderer.rs b/mingling_core/src/renderer.rs index 33dd08d..435518d 100644 --- a/mingling_core/src/renderer.rs +++ b/mingling_core/src/renderer.rs @@ -1,3 +1,3 @@ -#[cfg(feature = "general_renderer")] -pub mod general; +#[cfg(feature = "structural_renderer")] +pub mod structural; pub mod render_result; diff --git a/mingling_core/src/renderer/general.rs b/mingling_core/src/renderer/general.rs deleted file mode 100644 index e6da06b..0000000 --- a/mingling_core/src/renderer/general.rs +++ /dev/null @@ -1,268 +0,0 @@ -use crate::{ - GeneralRendererSetting, RenderResult, renderer::general::error::GeneralRendererSerializeError, -}; -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 [`StructuralData`] trait (which implies `Serialize`). -pub struct GeneralRenderer; - -impl GeneralRenderer { - /// Renders data in the specified format to the given `RenderResult`. - /// - /// # Errors - /// - /// Returns `Err(GeneralRendererSerializeError)` if serialization fails. - #[allow(unused_variables)] - pub fn render( - data: &T, - setting: &GeneralRendererSetting, - r: &mut RenderResult, - ) -> Result<(), GeneralRendererSerializeError> { - match setting { - GeneralRendererSetting::Disable => Ok(()), - #[cfg(feature = "json_serde_fmt")] - GeneralRendererSetting::Json => Self::render_to_json(data, r), - #[cfg(feature = "json_serde_fmt")] - GeneralRendererSetting::JsonPretty => Self::render_to_json_pretty(data, r), - #[cfg(feature = "yaml_serde_fmt")] - GeneralRendererSetting::Yaml => Self::render_to_yaml(data, r), - #[cfg(feature = "toml_serde_fmt")] - GeneralRendererSetting::Toml => Self::render_to_toml(data, r), - #[cfg(feature = "ron_serde_fmt")] - GeneralRendererSetting::Ron => Self::render_to_ron(data, r), - #[cfg(feature = "ron_serde_fmt")] - GeneralRendererSetting::RonPretty => Self::render_to_ron_pretty(data, r), - } - } - - /// Serializes data to JSON format and writes it to the render result. - /// - /// # Errors - /// - /// Returns `Err(GeneralRendererSerializeError)` if serialization fails. - #[cfg(feature = "json_serde_fmt")] - fn render_to_json( - 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); - Ok(()) - } - - /// Serializes data to pretty-printed JSON format and writes it to the render result. - /// - /// # Errors - /// - /// Returns `Err(GeneralRendererSerializeError)` if serialization fails. - #[cfg(feature = "json_serde_fmt")] - fn render_to_json_pretty( - 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); - Ok(()) - } - - /// Serializes data to RON format and writes it to the render result. - /// - /// # Errors - /// - /// Returns `Err(GeneralRendererSerializeError)` if serialization fails. - #[cfg(feature = "ron_serde_fmt")] - fn render_to_ron( - 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); - Ok(()) - } - - /// Serializes data to pretty-printed RON format and writes it to the render result. - /// - /// # Errors - /// - /// Returns `Err(GeneralRendererSerializeError)` if serialization fails. - #[cfg(feature = "ron_serde_fmt")] - fn render_to_ron_pretty( - data: &T, - r: &mut RenderResult, - ) -> Result<(), GeneralRendererSerializeError> { - 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); - Ok(()) - } - - /// Serializes data to TOML format and writes it to the render result. - /// - /// # Errors - /// - /// Returns `Err(GeneralRendererSerializeError)` if serialization fails. - #[cfg(feature = "toml_serde_fmt")] - fn render_to_toml( - 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); - Ok(()) - } - - /// Serializes data to YAML format and writes it to the render result. - /// - /// # Errors - /// - /// Returns `Err(GeneralRendererSerializeError)` if serialization fails. - #[cfg(feature = "yaml_serde_fmt")] - fn render_to_yaml( - 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); - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::RenderResult; - use serde::Serialize; - - #[derive(Debug, Clone, PartialEq, Serialize)] - struct TestData { - name: String, - value: i32, - } - - impl crate::__private::StructuralDataSealed for TestData {} - impl StructuralData for TestData {} - - fn test_data() -> TestData { - TestData { - name: "hello".into(), - value: 42, - } - } - - #[test] - fn test_render_disable_does_nothing() { - let mut r = RenderResult::default(); - let result = - GeneralRenderer::render(&test_data(), &GeneralRendererSetting::Disable, &mut r); - assert!(result.is_ok()); - assert!(r.is_empty()); - } - - #[cfg(feature = "json_serde_fmt")] - #[test] - fn test_render_to_json() { - let mut r = RenderResult::default(); - let result = - GeneralRenderer::render(&test_data(), &GeneralRendererSetting::Json, &mut r); - assert!(result.is_ok()); - assert!(!r.is_empty()); - let output: String = r.into(); - assert!(output.contains("\"name\"")); - assert!(output.contains("\"hello\"")); - assert!(output.contains("\"value\"")); - assert!(output.contains("42")); - } - - #[cfg(feature = "json_serde_fmt")] - #[test] - fn test_render_to_json_pretty() { - let mut r = RenderResult::default(); - let result = - GeneralRenderer::render(&test_data(), &GeneralRendererSetting::JsonPretty, &mut r); - assert!(result.is_ok()); - let output: String = r.into(); - // Pretty JSON has newlines - assert!(output.contains('\n')); - } - - #[cfg(feature = "yaml_serde_fmt")] - #[test] - fn test_render_to_yaml() { - let mut r = RenderResult::default(); - let result = - GeneralRenderer::render(&test_data(), &GeneralRendererSetting::Yaml, &mut r); - assert!(result.is_ok()); - assert!(!r.is_empty()); - } - - #[cfg(feature = "toml_serde_fmt")] - #[test] - fn test_render_to_toml() { - let mut r = RenderResult::default(); - let result = - GeneralRenderer::render(&test_data(), &GeneralRendererSetting::Toml, &mut r); - assert!(result.is_ok()); - assert!(!r.is_empty()); - } - - #[cfg(feature = "ron_serde_fmt")] - #[test] - fn test_render_to_ron() { - let mut r = RenderResult::default(); - let result = - GeneralRenderer::render(&test_data(), &GeneralRendererSetting::Ron, &mut r); - assert!(result.is_ok()); - assert!(!r.is_empty()); - } - - #[cfg(feature = "ron_serde_fmt")] - #[test] - fn test_render_to_ron_pretty() { - let mut r = RenderResult::default(); - let result = - GeneralRenderer::render(&test_data(), &GeneralRendererSetting::RonPretty, &mut r); - assert!(result.is_ok()); - let output: String = r.into(); - assert!(output.contains('\n')); - } - - #[test] - fn test_render_dispatches_correct_format() { - // Test that render dispatches to the right format handler - let mut r = RenderResult::default(); - - // Disable - let result = - GeneralRenderer::render(&test_data(), &GeneralRendererSetting::Disable, &mut r); - assert!(result.is_ok()); - assert!(r.is_empty()); - } - - #[cfg(feature = "json_serde_fmt")] - #[test] - fn test_render_dispatches_json() { - let mut r = RenderResult::default(); - let result = GeneralRenderer::render(&test_data(), &GeneralRendererSetting::Json, &mut r); - assert!(result.is_ok()); - assert!(!r.is_empty()); - } -} diff --git a/mingling_core/src/renderer/general/error.rs b/mingling_core/src/renderer/general/error.rs deleted file mode 100644 index 07ca92b..0000000 --- a/mingling_core/src/renderer/general/error.rs +++ /dev/null @@ -1,68 +0,0 @@ -/// Represents an error that occurs during serialization of a general renderer. -/// -/// This error stores a human-readable message describing what went wrong -/// during the serialization process. -#[derive(Debug)] -pub struct GeneralRendererSerializeError { - /// The underlying error message. - error: String, -} - -impl GeneralRendererSerializeError { - #[must_use] - pub fn new(error: String) -> Self { - Self { error } - } -} - -impl From<&str> for GeneralRendererSerializeError { - fn from(s: &str) -> Self { - Self::new(s.to_string()) - } -} - -impl std::ops::Deref for GeneralRendererSerializeError { - type Target = String; - - fn deref(&self) -> &Self::Target { - &self.error - } -} - -impl From for String { - fn from(val: GeneralRendererSerializeError) -> Self { - val.error - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn new_creates_error_with_message() { - let msg = "serialization failed".to_string(); - let err = GeneralRendererSerializeError::new(msg.clone()); - assert_eq!(err.error, msg); - } - - #[test] - fn from_str_creates_error_from_string_slice() { - let err: GeneralRendererSerializeError = "oops".into(); - assert_eq!(err.error, "oops"); - } - - #[test] - fn deref_accesses_inner_error_string() { - let err = GeneralRendererSerializeError::new("inner message".to_string()); - let derefed: &String = &err; - assert_eq!(derefed, "inner message"); - } - - #[test] - fn into_string_extracts_message() { - let err = GeneralRendererSerializeError::new("extract me".to_string()); - let s: String = err.into(); - assert_eq!(s, "extract me"); - } -} diff --git a/mingling_core/src/renderer/general/structural_data.rs b/mingling_core/src/renderer/general/structural_data.rs deleted file mode 100644 index ac6363e..0000000 --- a/mingling_core/src/renderer/general/structural_data.rs +++ /dev/null @@ -1,15 +0,0 @@ -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 {} diff --git a/mingling_core/src/renderer/structural.rs b/mingling_core/src/renderer/structural.rs new file mode 100644 index 0000000..16ce471 --- /dev/null +++ b/mingling_core/src/renderer/structural.rs @@ -0,0 +1,268 @@ +use crate::{ + StructuralRendererSetting, RenderResult, renderer::structural::error::StructuralRendererSerializeError, +}; +use serde::Serialize; + +pub mod error; +pub mod structural_data; + +use structural_data::StructuralData; + +/// A structural renderer that supports multiple serialization formats. +/// +/// The `StructuralRenderer` 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 [`StructuralData`] trait (which implies `Serialize`). +pub struct StructuralRenderer; + +impl StructuralRenderer { + /// Renders data in the specified format to the given `RenderResult`. + /// + /// # Errors + /// + /// Returns `Err(StructuralRendererSerializeError)` if serialization fails. + #[allow(unused_variables)] + pub fn render( + data: &T, + setting: &StructuralRendererSetting, + r: &mut RenderResult, + ) -> Result<(), StructuralRendererSerializeError> { + match setting { + StructuralRendererSetting::Disable => Ok(()), + #[cfg(feature = "json_serde_fmt")] + StructuralRendererSetting::Json => Self::render_to_json(data, r), + #[cfg(feature = "json_serde_fmt")] + StructuralRendererSetting::JsonPretty => Self::render_to_json_pretty(data, r), + #[cfg(feature = "yaml_serde_fmt")] + StructuralRendererSetting::Yaml => Self::render_to_yaml(data, r), + #[cfg(feature = "toml_serde_fmt")] + StructuralRendererSetting::Toml => Self::render_to_toml(data, r), + #[cfg(feature = "ron_serde_fmt")] + StructuralRendererSetting::Ron => Self::render_to_ron(data, r), + #[cfg(feature = "ron_serde_fmt")] + StructuralRendererSetting::RonPretty => Self::render_to_ron_pretty(data, r), + } + } + + /// Serializes data to JSON format and writes it to the render result. + /// + /// # Errors + /// + /// Returns `Err(StructuralRendererSerializeError)` if serialization fails. + #[cfg(feature = "json_serde_fmt")] + fn render_to_json( + data: &T, + r: &mut RenderResult, + ) -> Result<(), StructuralRendererSerializeError> { + let json_string = serde_json::to_string(data) + .map_err(|e| StructuralRendererSerializeError::new(e.to_string()))?; + r.print(&json_string); + Ok(()) + } + + /// Serializes data to pretty-printed JSON format and writes it to the render result. + /// + /// # Errors + /// + /// Returns `Err(StructuralRendererSerializeError)` if serialization fails. + #[cfg(feature = "json_serde_fmt")] + fn render_to_json_pretty( + data: &T, + r: &mut RenderResult, + ) -> Result<(), StructuralRendererSerializeError> { + let json_string = serde_json::to_string_pretty(data) + .map_err(|e| StructuralRendererSerializeError::new(e.to_string()))?; + r.print(&json_string); + Ok(()) + } + + /// Serializes data to RON format and writes it to the render result. + /// + /// # Errors + /// + /// Returns `Err(StructuralRendererSerializeError)` if serialization fails. + #[cfg(feature = "ron_serde_fmt")] + fn render_to_ron( + data: &T, + r: &mut RenderResult, + ) -> Result<(), StructuralRendererSerializeError> { + let ron_string = ron::ser::to_string(data) + .map_err(|e| StructuralRendererSerializeError::new(e.to_string()))?; + r.print(&ron_string); + Ok(()) + } + + /// Serializes data to pretty-printed RON format and writes it to the render result. + /// + /// # Errors + /// + /// Returns `Err(StructuralRendererSerializeError)` if serialization fails. + #[cfg(feature = "ron_serde_fmt")] + fn render_to_ron_pretty( + data: &T, + r: &mut RenderResult, + ) -> Result<(), StructuralRendererSerializeError> { + 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| StructuralRendererSerializeError::new(e.to_string()))?; + r.print(&ron_string); + Ok(()) + } + + /// Serializes data to TOML format and writes it to the render result. + /// + /// # Errors + /// + /// Returns `Err(StructuralRendererSerializeError)` if serialization fails. + #[cfg(feature = "toml_serde_fmt")] + fn render_to_toml( + data: &T, + r: &mut RenderResult, + ) -> Result<(), StructuralRendererSerializeError> { + let toml_string = + toml::to_string(data).map_err(|e| StructuralRendererSerializeError::new(e.to_string()))?; + r.print(&toml_string); + Ok(()) + } + + /// Serializes data to YAML format and writes it to the render result. + /// + /// # Errors + /// + /// Returns `Err(StructuralRendererSerializeError)` if serialization fails. + #[cfg(feature = "yaml_serde_fmt")] + fn render_to_yaml( + data: &T, + r: &mut RenderResult, + ) -> Result<(), StructuralRendererSerializeError> { + let yaml_string = serde_yaml::to_string(data) + .map_err(|e| StructuralRendererSerializeError::new(e.to_string()))?; + r.print(&yaml_string); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::RenderResult; + use serde::Serialize; + + #[derive(Debug, Clone, PartialEq, Serialize)] + struct TestData { + name: String, + value: i32, + } + + impl crate::__private::StructuralDataSealed for TestData {} + impl StructuralData for TestData {} + + fn test_data() -> TestData { + TestData { + name: "hello".into(), + value: 42, + } + } + + #[test] + fn test_render_disable_does_nothing() { + let mut r = RenderResult::default(); + let result = + StructuralRenderer::render(&test_data(), &StructuralRendererSetting::Disable, &mut r); + assert!(result.is_ok()); + assert!(r.is_empty()); + } + + #[cfg(feature = "json_serde_fmt")] + #[test] + fn test_render_to_json() { + let mut r = RenderResult::default(); + let result = + StructuralRenderer::render(&test_data(), &StructuralRendererSetting::Json, &mut r); + assert!(result.is_ok()); + assert!(!r.is_empty()); + let output: String = r.into(); + assert!(output.contains("\"name\"")); + assert!(output.contains("\"hello\"")); + assert!(output.contains("\"value\"")); + assert!(output.contains("42")); + } + + #[cfg(feature = "json_serde_fmt")] + #[test] + fn test_render_to_json_pretty() { + let mut r = RenderResult::default(); + let result = + StructuralRenderer::render(&test_data(), &StructuralRendererSetting::JsonPretty, &mut r); + assert!(result.is_ok()); + let output: String = r.into(); + // Pretty JSON has newlines + assert!(output.contains('\n')); + } + + #[cfg(feature = "yaml_serde_fmt")] + #[test] + fn test_render_to_yaml() { + let mut r = RenderResult::default(); + let result = + StructuralRenderer::render(&test_data(), &StructuralRendererSetting::Yaml, &mut r); + assert!(result.is_ok()); + assert!(!r.is_empty()); + } + + #[cfg(feature = "toml_serde_fmt")] + #[test] + fn test_render_to_toml() { + let mut r = RenderResult::default(); + let result = + StructuralRenderer::render(&test_data(), &StructuralRendererSetting::Toml, &mut r); + assert!(result.is_ok()); + assert!(!r.is_empty()); + } + + #[cfg(feature = "ron_serde_fmt")] + #[test] + fn test_render_to_ron() { + let mut r = RenderResult::default(); + let result = + StructuralRenderer::render(&test_data(), &StructuralRendererSetting::Ron, &mut r); + assert!(result.is_ok()); + assert!(!r.is_empty()); + } + + #[cfg(feature = "ron_serde_fmt")] + #[test] + fn test_render_to_ron_pretty() { + let mut r = RenderResult::default(); + let result = + StructuralRenderer::render(&test_data(), &StructuralRendererSetting::RonPretty, &mut r); + assert!(result.is_ok()); + let output: String = r.into(); + assert!(output.contains('\n')); + } + + #[test] + fn test_render_dispatches_correct_format() { + // Test that render dispatches to the right format handler + let mut r = RenderResult::default(); + + // Disable + let result = + StructuralRenderer::render(&test_data(), &StructuralRendererSetting::Disable, &mut r); + assert!(result.is_ok()); + assert!(r.is_empty()); + } + + #[cfg(feature = "json_serde_fmt")] + #[test] + fn test_render_dispatches_json() { + let mut r = RenderResult::default(); + let result = StructuralRenderer::render(&test_data(), &StructuralRendererSetting::Json, &mut r); + assert!(result.is_ok()); + assert!(!r.is_empty()); + } +} diff --git a/mingling_core/src/renderer/structural/error.rs b/mingling_core/src/renderer/structural/error.rs new file mode 100644 index 0000000..a7fbc75 --- /dev/null +++ b/mingling_core/src/renderer/structural/error.rs @@ -0,0 +1,68 @@ +/// Represents an error that occurs during serialization of a structural renderer. +/// +/// This error stores a human-readable message describing what went wrong +/// during the serialization process. +#[derive(Debug)] +pub struct StructuralRendererSerializeError { + /// The underlying error message. + error: String, +} + +impl StructuralRendererSerializeError { + #[must_use] + pub fn new(error: String) -> Self { + Self { error } + } +} + +impl From<&str> for StructuralRendererSerializeError { + fn from(s: &str) -> Self { + Self::new(s.to_string()) + } +} + +impl std::ops::Deref for StructuralRendererSerializeError { + type Target = String; + + fn deref(&self) -> &Self::Target { + &self.error + } +} + +impl From for String { + fn from(val: StructuralRendererSerializeError) -> Self { + val.error + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn new_creates_error_with_message() { + let msg = "serialization failed".to_string(); + let err = StructuralRendererSerializeError::new(msg.clone()); + assert_eq!(err.error, msg); + } + + #[test] + fn from_str_creates_error_from_string_slice() { + let err: StructuralRendererSerializeError = "oops".into(); + assert_eq!(err.error, "oops"); + } + + #[test] + fn deref_accesses_inner_error_string() { + let err = StructuralRendererSerializeError::new("inner message".to_string()); + let derefed: &String = &err; + assert_eq!(derefed, "inner message"); + } + + #[test] + fn into_string_extracts_message() { + let err = StructuralRendererSerializeError::new("extract me".to_string()); + let s: String = err.into(); + assert_eq!(s, "extract me"); + } +} diff --git a/mingling_core/src/renderer/structural/structural_data.rs b/mingling_core/src/renderer/structural/structural_data.rs new file mode 100644 index 0000000..1cafac3 --- /dev/null +++ b/mingling_core/src/renderer/structural/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 `structural_render` match arm to be generated. +#[doc(hidden)] +pub trait StructuralData: Serialize + crate::__private::StructuralDataSealed {} -- cgit