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 --- CHANGELOG.md | 51 ++-- README.md | 16 +- dev_tools/scripts/doc.ps1 | 2 +- dev_tools/scripts/doc.sh | 2 +- docs/_zh_CN/pages/other/features.md | 10 +- docs/_zh_CN/pages/other/naming_rule.md | 2 +- docs/example-pages/examples.json | 36 +-- docs/pages/other/features.md | 16 +- docs/pages/other/naming_rule.md | 2 +- examples/example-general-renderer/Cargo.lock | 148 ----------- examples/example-general-renderer/Cargo.toml | 16 -- examples/example-general-renderer/page.toml | 10 - examples/example-general-renderer/src/main.rs | 71 ----- examples/example-pack-err/Cargo.toml | 2 +- examples/example-pack-err/page.toml | 4 +- examples/example-pack-err/src/main.rs | 10 +- examples/example-structural-renderer/Cargo.lock | 148 +++++++++++ examples/example-structural-renderer/Cargo.toml | 16 ++ examples/example-structural-renderer/page.toml | 10 + examples/example-structural-renderer/src/main.rs | 71 +++++ examples/full-todolist/Cargo.toml | 2 +- examples/full-todolist/src/main.rs | 4 +- examples/test-examples.toml | 4 +- mingling/Cargo.toml | 20 +- mingling/src/example_docs.rs | 202 +++++++-------- mingling/src/features.rs | 66 ++--- mingling/src/lib.rs | 12 +- mingling/src/setups.rs | 8 +- mingling/src/setups/general_renderer.rs | 61 ----- mingling/src/setups/structural_renderer.rs | 61 +++++ mingling_core/Cargo.toml | 4 +- 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 ++ mingling_core/tests/test-all/Cargo.toml | 2 +- mingling_core/tests/test-all/tests/integration.rs | 14 +- .../tests/test-general-renderer/Cargo.lock | 287 --------------------- .../tests/test-general-renderer/Cargo.toml | 11 - .../test-general-renderer/tests/integration.rs | 75 ------ .../tests/test-structural-renderer/Cargo.lock | 287 +++++++++++++++++++++ .../tests/test-structural-renderer/Cargo.toml | 11 + .../test-structural-renderer/tests/integration.rs | 75 ++++++ mingling_macros/Cargo.toml | 2 +- mingling_macros/src/groupped.rs | 2 +- mingling_macros/src/lib.rs | 76 +++--- mingling_macros/src/pack.rs | 2 +- mingling_macros/src/pack_err.rs | 6 +- mingling_macros/src/renderer.rs | 26 +- mingling_macros/src/structural_data.rs | 8 +- mling/Cargo.toml | 2 +- mling/src/cli.rs | 4 +- 67 files changed, 1461 insertions(+), 1442 deletions(-) delete mode 100644 examples/example-general-renderer/Cargo.lock delete mode 100644 examples/example-general-renderer/Cargo.toml delete mode 100644 examples/example-general-renderer/page.toml delete mode 100644 examples/example-general-renderer/src/main.rs create mode 100644 examples/example-structural-renderer/Cargo.lock create mode 100644 examples/example-structural-renderer/Cargo.toml create mode 100644 examples/example-structural-renderer/page.toml create mode 100644 examples/example-structural-renderer/src/main.rs delete mode 100644 mingling/src/setups/general_renderer.rs create mode 100644 mingling/src/setups/structural_renderer.rs 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 delete mode 100644 mingling_core/tests/test-general-renderer/Cargo.lock delete mode 100644 mingling_core/tests/test-general-renderer/Cargo.toml delete mode 100644 mingling_core/tests/test-general-renderer/tests/integration.rs create mode 100644 mingling_core/tests/test-structural-renderer/Cargo.lock create mode 100644 mingling_core/tests/test-structural-renderer/Cargo.toml create mode 100644 mingling_core/tests/test-structural-renderer/tests/integration.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index c1ad00b..8bee517 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,12 +19,12 @@ - **Global resource** (`global_resource.rs`): `GlobalResource` new, Deref, AsRef; three default implementations of `ResourceMarker` - **Lazy resource** (`lazy_resource.rs`): Coverage of all 18+ methods of `LazyRes`, including initialization triggering, get_ref/get_mut/get_clone, into_inner/unwrap, Drop callback, `ResourceMarker` integration - **Error types** (`chain/error.rs`, `program/error.rs`): All Display, Error source, From conversions - - **Configuration structs** (`config.rs`): Default values for `ProgramStdoutSetting`, `ProgramUserContext`; FromStr parsing and Display output of `GeneralRendererSetting` (feature-gated) + - **Configuration structs** (`config.rs`): Default values for `ProgramStdoutSetting`, `ProgramUserContext`; FromStr parsing and Display output of `StructuralRendererSetting` (feature-gated) - **Flag system** (`flag.rs`): Added 8 From conversions, Deref, AsRef for `Flag` - **String wrapper** (`string_vec.rs`): 6 From conversions, Deref, Into\ - **Render result** (`render_result.rs`): print/println/clear/is_empty, Write trait, Display, Deref, From conversions - - **Render error** (`general/error.rs`): Construction, From, Deref, Into\ - - **General renderer** (`general.rs`): Rendering in Disable/JSON/YAML/TOML/RON formats (feature-gated) + - **Render error** (`structural/error.rs`): Construction, From, Deref, Into\ + - **Structural renderer** (`structural.rs`): Rendering in Disable/JSON/YAML/TOML/RON formats (feature-gated) - **Completion suggestions** (`suggest.rs`): All construction, access, modification, sorting, and conversion methods for `Suggest` and `SuggestItem` - **Shell context** (`shell_ctx.rs`): Added `filling_argument`, `filling_argument_first`, `typing_argument`, `strip_typed_argument`, `get_typed_arguments` - **Hook system** (`hook.rs`): `ProgramHook::empty` and all 8 builder methods @@ -37,10 +37,10 @@ - `test-basic`: Basic type tests with default features (Node, Flag, RenderResult, NextProcess, StringVec) - `test-comp`: ShellContext, Suggest, SuggestItem, is_completing with `comp + builds` features - - `test-general-renderer`: GeneralRenderer output in various formats with `general_renderer_full + parser` features + - `test-structural-renderer`: StructuralRenderer output in various formats with `structural_renderer_full + parser` features - `test-repl`: ResREPL and basic types with `repl + extra_macros` features - `test-dispatch-tree`: Basic types with `dispatch_tree` feature - - `test-all`: Comprehensive testing with all feature combinations (ShellContext, Suggest, ResREPL, GeneralRenderer, Hooks, basic types, etc.) + - `test-all`: Comprehensive testing with all feature combinations (ShellContext, Suggest, ResREPL, StructuralRenderer, Hooks, basic types, etc.) These crates are located in `mingling_core/tests/test-*/`, each marked as an independent workspace via `[workspace]`, isolated from the main workspace. @@ -264,9 +264,28 @@ The following explicit syntaxes are **removed**: --- -1. **\[core\]** Changed the signature of `ProgramSetup::setup` from `fn setup(&mut self, program: &mut Program) -> S` to `fn setup(self, program: &mut Program)`, consuming `self` instead of taking a mutable reference. Correspondingly, `Program::with_setup` now accepts `S` by value (`&mut self, setup: S`) instead of by mutable reference (`&mut self, setup: &mut S`). - -2. **\[core\]** Consolidated resource naming for `ExitCode` and `REPL`: +1. **\[core\]** **\[structural_renderer\]** Renamed the `general_renderer` feature to `structural_renderer`. All associated types, structs, and APIs have been renamed accordingly: + + - Feature flag: `general_renderer` → `structural_renderer` + - Setup struct: `GeneralRendererSetup` → `StructuralRendererSetup` + - Simple setup struct: `GeneralRendererSimpleSetup` → `StructuralRendererSimpleSetup` + - Renderer type: `GeneralRenderer` → `StructuralRenderer` + - Setting enum: `GeneralRendererSetting` → `StructuralRendererSetting` + - Error type: `GeneralRendererSerializeError` → `StructuralRendererSerializeError` + - Field name: `program.general_renderer_name` → `program.structural_renderer_name` + - Trait method: `ProgramCollect::general_render()` → `ProgramCollect::structural_render()` + - Internal module: `mingling_core::renderer::general` → `mingling::renderer::structural` + - Internal static: `GENERAL_RENDERERS` → `STRUCTURAL_RENDERERS` + - Feature gate attributes: `#[cfg(feature = "general_renderer")]` → `#[cfg(feature = "structural_renderer")]` + - Sub-features: `general_renderer_empty` → `structural_renderer_empty`, `general_renderer_full` → `structural_renderer_full` + - Runtime feature constant: `MINGLING_GENERAL_RENDERER` → `MINGLING_STRUCTURAL_RENDERER` (and similarly for `_EMPTY` and `_FULL`) + - Derive macro feature gate: `#[cfg(feature = "general_renderer")]` on `#[derive(StructuralData)]` and `#[derive(GrouppedSerialize)]` → `#[cfg(feature = "structural_renderer")]` + - Example project: `example-general-renderer` renamed to `example-structural-renderer` + - Test crate: `test-general-renderer` renamed to `test-structural-renderer` + +2. **\[core\]** Changed the signature of `ProgramSetup::setup` from `fn setup(&mut self, program: &mut Program) -> S` to `fn setup(self, program: &mut Program)`, consuming `self` instead of taking a mutable reference. Correspondingly, `Program::with_setup` now accepts `S` by value (`&mut self, setup: S`) instead of by mutable reference (`&mut self, setup: &mut S`). + +3. **\[core\]** Consolidated resource naming for `ExitCode` and `REPL`: - Renamed `ExitCode` to `ResExitCode` and moved `ResREPL` from the `mingling` root to `mingling::res::ResREPL` (the `mingling::ResREPL` re-export is removed). - This aligns with the naming convention where resources are prefixed with `Res`. - The corresponding setup `ExitCodeSetup` and resource injection remain unchanged. @@ -279,7 +298,7 @@ use mingling::{res::ExitCode, REPL}; use mingling::{res::ResExitCode, res::ResREPL}; ``` -3. **\[core\]** **\[macros\]** Migrated `to_chain()` and `to_render()` methods from being generated individually per type by `#[derive(Groupped)]` and `pack!` macros, to being provided as default trait methods on the `Groupped` trait itself. +4. **\[core\]** **\[macros\]** Migrated `to_chain()` and `to_render()` methods from being generated individually per type by `#[derive(Groupped)]` and `pack!` macros, to being provided as default trait methods on the `Groupped` trait itself. Previously, each packed or derived type had its own inherent `to_chain()` and `to_render()` methods generated by the macros. Now, these methods are defined on the `Groupped` trait with default implementations, making them available to all types that implement the trait without redundant code generation. @@ -301,7 +320,7 @@ use mingling::{res::ResExitCode, res::ResREPL}; Removed the per-type inherent method generation from both `groupped.rs` and `pack.rs` in `mingling_macros`. -4. **\[macros\]** Changed the `route!()` macro's error branch from `return e` to `return ::mingling::Groupped::to_chain(e)`, so that the error type no longer needs to be pre-converted to `ChainProcess` via `.to_chain()` or `.to_render()`. The macro now accepts any type implementing `Groupped` in the error position and automatically converts it. +5. **\[macros\]** Changed the `route!()` macro's error branch from `return e` to `return ::mingling::Groupped::to_chain(e)`, so that the error type no longer needs to be pre-converted to `ChainProcess` via `.to_chain()` or `.to_render()`. The macro now accepts any type implementing `Groupped` in the error position and automatically converts it. ```rust // Before @@ -311,7 +330,7 @@ let value = route!(prev.pick_or_route((), Error::default().to_chain()).unpack()) let value = route!(prev.pick_or_route((), Error::default()).unpack()); ``` -5. **\[core\]** **\[hook\]** Refactored the hook system to use structured info types and return `ProgramControls` instead of raw values. +6. **\[core\]** **\[hook\]** Refactored the hook system to use structured info types and return `ProgramControls` instead of raw values. The hook system has been redesigned for better type safety, extensibility, and control flow management: @@ -351,15 +370,15 @@ let value = route!(prev.pick_or_route((), Error::default()).unpack()); - **Examples and internal callers updated** throughout the codebase to use the new hook API patterns. -6. **\[core\]** **\[general_renderer\]** Added the `pack_err_structural!`, `pack_structural!`, and `group_structural!` macros for creating types that support structured output (JSON/YAML/TOML/RON). These are like `pack_err!`, `pack!`, and `group!` respectively, but also mark the type with the `StructuralData` trait, enabling the `GeneralRenderer` to serialize them. +7. **\[core\]** **\[structural_renderer\]** Added the `pack_err_structural!`, `pack_structural!`, and `group_structural!` macros for creating types that support structured output (JSON/YAML/TOML/RON). These are like `pack_err!`, `pack!`, and `group!` respectively, but also mark the type with the `StructuralData` trait, enabling the `StructuralRenderer` to serialize them. -7. **\[core\]** **\[general_renderer\]** Added the `StructuralData` derive macro and sealed trait, decoupling structured output from `Groupped`. Previously, under the `general_renderer` feature, all `pack!` and `pack_err!` types automatically derived `Serialize`. Now, structured output is an opt-in property controlled by `StructuralData`: - - `pack!` / `pack_err!` / `group!` no longer derive `Serialize` even when `general_renderer` is enabled. +8. **\[core\]** **\[structural_renderer\]** Added the `StructuralData` derive macro and sealed trait, decoupling structured output from `Groupped`. Previously, under the `structural_renderer` feature, all `pack!` and `pack_err!` types automatically derived `Serialize`. Now, structured output is an opt-in property controlled by `StructuralData`: + - `pack!` / `pack_err!` / `group!` no longer derive `Serialize` even when `structural_renderer` is enabled. - To enable structured output, use `pack_structural!` / `pack_err_structural!` / `group_structural!` or the `#[derive(StructuralData)]` marker. - The `Groupped` trait no longer requires `Serialize` bounds, and `AnyOutput::new` no longer requires `Serialize`. - - `GeneralRenderer::render` now accepts `T: StructuralData + Send` instead of `T: Serialize + Send`, and the individual format methods (`render_to_json`, etc.) are now private. + - `StructuralRenderer::render` now accepts `T: StructuralData + Send` instead of `T: Serialize + Send`, and the individual format methods (`render_to_json`, etc.) are now private. -8. **\[core\]** **\[general_renderer\]** Added `mingling::__private::StructuralDataSealed` and `mingling::__private::StructuralData` (re-exported from `mingling_core::renderer::general::structural_data`) to support the sealed trait pattern. The `StructuralData` trait is only implementable via the derive macro or the `_structural` macro variants. +9. **\[core\]** **\[structural_renderer\]** Added `mingling::__private::StructuralDataSealed` and `mingling::__private::StructuralData` (re-exported from `mingling_core::renderer::structural::structural_data`) to support the sealed trait pattern. The `StructuralData` trait is only implementable via the derive macro or the `_structural` macro variants. ### Release 0.1.9 (2026-05-29) diff --git a/README.md b/README.md index f6e782d..4f4531b 100644 --- a/README.md +++ b/README.md @@ -48,8 +48,8 @@ 4. **Lightning-Fast Subcommand Dispatch**: With the `dispatch_tree` feature, Mingling hardens the subcommand structure into a prefix tree at **compile time**, enabling blazing-fast subcommand lookup. See examples: [Example](https://github.com/mingling-rs/mingling/blob/main/examples/example-dispatch-tree/src/main.rs) 5. **Lightweight Dependencies, On-Demand Importing**: Minimal core dependencies keep builds fast; enhanced features are imported on demand through fine-grained feature flags. -6. **Structured Output**: Enabling the `general_renderer` feature adds support for flags like `--json` and `--yaml`, providing structured output capabilities. - See examples: [Example](https://github.com/mingling-rs/mingling/blob/main/examples/example-general-renderer/src/main.rs) +6. **Structured Output**: Enabling the `structural_renderer` feature adds support for flags like `--json` and `--yaml`, providing structured output capabilities. + See examples: [Example](https://github.com/mingling-rs/mingling/blob/main/examples/example-structural-renderer/src/main.rs)

✍️ Writing with Mingling ✍️ @@ -658,16 +658,16 @@ fn main() { --- -### 13. General Renderer — Structured Output (JSON/YAML) +### 13. Structural Renderer — Structured Output (JSON/YAML) -With the `general_renderer` feature, users can add `--json` or `--yaml` flags to get structured output instead of human-readable text. +With the `structural_renderer` feature, users can add `--json` or `--yaml` flags to get structured output instead of human-readable text. ```rust -// Features: ["general_renderer", "parser"] +// Features: ["structural_renderer", "parser"] // Dependencies: // serde = "1" -use mingling::{prelude::*, setup::GeneralRendererSetup}; +use mingling::{prelude::*, setup::StructuralRendererSetup}; use mingling::Groupped; use mingling::StructuralData; use serde::Serialize; @@ -693,7 +693,7 @@ fn render_info_result(info: ResultInfo) { fn main() { let mut program = ThisProgram::new(); - program.with_setup(GeneralRendererSetup); // enables --json / --yaml + program.with_setup(StructuralRendererSetup); // enables --json / --yaml program.with_dispatcher(CMDRender); let _ = program.exec(); } @@ -848,7 +848,7 @@ Then check out:

- [ ] Milestone.1 "MVP" - - [x] \[[0.1.4](https://docs.rs/mingling/0.1.4/mingling/)\] \[`core`\] \[`general_renderer`\] **Mingling** can render data into serializable formats via `--json` and `--yaml` flags + - [x] \[[0.1.4](https://docs.rs/mingling/0.1.4/mingling/)\] \[`core`\] \[`structural_renderer`\] **Mingling** can render data into serializable formats via `--json` and `--yaml` flags - [x] \[[0.1.5](https://docs.rs/mingling/0.1.5/mingling/)\] \[`core`\] \[`comp`\] **Mingling** can dynamically invoke itself to provide completions for shells like `bash`, `zsh`, `fish`, and `pwsh` - [x] \[[0.1.6](https://docs.rs/mingling/0.1.6/mingling/)\] \[`core`\] \[`comp`\] **Mingling** can gather more context for smarter completions - [x] \[[0.1.7](https://docs.rs/mingling/0.1.7/mingling/)\] \[`clap`\] Provides a **Clap** compatibility layer, allowing **Mingling** to reuse its powerful parsing capabilities diff --git a/dev_tools/scripts/doc.ps1 b/dev_tools/scripts/doc.ps1 index 20b2173..987f0de 100755 --- a/dev_tools/scripts/doc.ps1 +++ b/dev_tools/scripts/doc.ps1 @@ -1 +1 @@ -cargo doc --workspace --no-deps --features builds,general_renderer,repl,comp,parser,clap,extra_macros --open +cargo doc --workspace --no-deps --features builds,structural_renderer,repl,comp,parser,clap,extra_macros --open diff --git a/dev_tools/scripts/doc.sh b/dev_tools/scripts/doc.sh index 9e67961..5e8a311 100755 --- a/dev_tools/scripts/doc.sh +++ b/dev_tools/scripts/doc.sh @@ -1,3 +1,3 @@ #!/bin/bash -cargo doc --workspace --no-deps --features builds,general_renderer,repl,comp,parser,clap,extra_macros --open +cargo doc --workspace --no-deps --features builds,structural_renderer,repl,comp,parser,clap,extra_macros --open diff --git a/docs/_zh_CN/pages/other/features.md b/docs/_zh_CN/pages/other/features.md index 558720c..cadffec 100644 --- a/docs/_zh_CN/pages/other/features.md +++ b/docs/_zh_CN/pages/other/features.md @@ -7,7 +7,7 @@ **介绍:** -为 `general_renderer` 启用所有序列化格式(JSON、RON、TOML、YAML)的 serde 格式化支持。 +为 `structural_renderer` 启用所有序列化格式(JSON、RON、TOML、YAML)的 serde 格式化支持。 开启此特性将自动启用 `json_serde_fmt`、`ron_serde_fmt`、`toml_serde_fmt`、`yaml_serde_fmt` 四个子特性。 @@ -208,7 +208,7 @@ pack_err!(ErrorNotDir = PathBuf); -## 特性 `general_renderer` +## 特性 `structural_renderer` **介绍:** @@ -216,15 +216,15 @@ pack_err!(ErrorNotDir = PathBuf); 开启后,用户可以通过 `--json` 或 `--yaml` 等标志获取结构化输出。 -详见 [示例](https://mingling-rs.github.io/mingling/docs/example-viewer.html?name=example-general-renderer) +详见 [示例](https://mingling-rs.github.io/mingling/docs/example-viewer.html?name=example-structural-renderer) -## 特性 `general_renderer_empty` +## 特性 `structural_renderer_empty` **介绍:** 启用通用渲染器的空实现版本,适用于不需要实际渲染功能的场景。此特性不启用任何 serde 格式化后端。 -## 特性 `general_renderer_full` +## 特性 `structural_renderer_full` **介绍:** diff --git a/docs/_zh_CN/pages/other/naming_rule.md b/docs/_zh_CN/pages/other/naming_rule.md index 18ebf3f..264cffd 100644 --- a/docs/_zh_CN/pages/other/naming_rule.md +++ b/docs/_zh_CN/pages/other/naming_rule.md @@ -36,7 +36,7 @@ Res + 名称 | 示例 | 说明 | | ---------------------- | ---------------------------------------------- | | `BasicSetup` | 基础初始化(`--quiet`、`--help`、`--confirm`) | -| `GeneralRendererSetup` | 通用渲染器初始化(`--json`、`--yaml` 等) | +| `StructuralRendererSetup` | 通用渲染器初始化(`--json`、`--yaml` 等) | ### 分发器 diff --git a/docs/example-pages/examples.json b/docs/example-pages/examples.json index 4d7c494..f3484f3 100644 --- a/docs/example-pages/examples.json +++ b/docs/example-pages/examples.json @@ -147,22 +147,6 @@ "Cargo.toml" ] }, - { - "id": "example-general-renderer", - "name": "General Renderer", - "icon": "📤", - "category": "output", - "desc": "Demonstrates how to render structured output in JSON or YAML using `GeneralRendererSetup` and the `general_renderer` feature.\n", - "tags": [ - "general_renderer", - "--json", - "--yaml" - ], - "files": [ - "src/main.rs", - "Cargo.toml" - ] - }, { "id": "example-help", "name": "Help", @@ -239,11 +223,11 @@ "name": "Pack an Error", "icon": "🛑", "category": "macros", - "desc": "Demonstrates how to use the `pack_err!` macro to define error types with automatic `name` field (snake_case at compile time) and optional `info` field. Also shows `--json` serialization when `general_renderer` is enabled.\n", + "desc": "Demonstrates how to use the `pack_err!` macro to define error types with automatic `name` field (snake_case at compile time) and optional `info` field. Also shows `--json` serialization when `structural_renderer` is enabled.\n", "tags": [ "pack_err!", "extra_macros", - "general_renderer", + "structural_renderer", "--json" ], "files": [ @@ -309,6 +293,22 @@ "Cargo.toml" ] }, + { + "id": "example-structural-renderer", + "name": "structural renderer", + "icon": "📤", + "category": "output", + "desc": "Demonstrates how to render structured output in JSON or YAML using `StructuralRendererSetup` and the `structural_renderer` feature.\n", + "tags": [ + "structural_renderer", + "--json", + "--yaml" + ], + "files": [ + "src/main.rs", + "Cargo.toml" + ] + }, { "id": "example-unit-test", "name": "Unit Test", diff --git a/docs/pages/other/features.md b/docs/pages/other/features.md index 5ee0497..ea5fc93 100644 --- a/docs/pages/other/features.md +++ b/docs/pages/other/features.md @@ -7,7 +7,7 @@ **Description:** -Enables serde formatting support for all serialization formats (JSON, RON, TOML, YAML) in `general_renderer`. +Enables serde formatting support for all serialization formats (JSON, RON, TOML, YAML) in `structural_renderer`. Enabling this feature will automatically enable the four sub-features: `json_serde_fmt`, `ron_serde_fmt`, `toml_serde_fmt`, `yaml_serde_fmt`. @@ -208,27 +208,27 @@ pack_err!(ErrorNotDir = PathBuf); -## Feature `general_renderer` +## Feature `structural_renderer` **Description:** -Enables the general renderer, providing basic content rendering capabilities. Enabling this feature will automatically enable `json_serde_fmt`. +Enables the structural renderer, providing basic content rendering capabilities. Enabling this feature will automatically enable `json_serde_fmt`. When enabled, users can get structured output via flags like `--json` or `--yaml`. -See [example](https://mingling-rs.github.io/mingling/docs/example-viewer.html?name=example-general-renderer) +See [example](https://mingling-rs.github.io/mingling/docs/example-viewer.html?name=example-structural-renderer) -## Feature `general_renderer_empty` +## Feature `structural_renderer_empty` **Description:** -Enables an empty implementation of the general renderer, suitable for scenarios where no actual rendering is needed. This feature does not enable any serde formatting backend. +Enables an empty implementation of the structural renderer, suitable for scenarios where no actual rendering is needed. This feature does not enable any serde formatting backend. -## Feature `general_renderer_full` +## Feature `structural_renderer_full` **Description:** -Enables the full implementation of the general renderer, including all rendering capabilities and serialization format support. Enabling this feature will automatically enable `all_serde_fmt`. +Enables the full implementation of the structural renderer, including all rendering capabilities and serialization format support. Enabling this feature will automatically enable `all_serde_fmt`. ## Feature `json_serde_fmt` diff --git a/docs/pages/other/naming_rule.md b/docs/pages/other/naming_rule.md index 9443481..4f4efe8 100644 --- a/docs/pages/other/naming_rule.md +++ b/docs/pages/other/naming_rule.md @@ -36,7 +36,7 @@ Name + Setup | Example | Description | | ---------------------- | ---------------------------------------------------------- | | `BasicSetup` | Basic initialization (`--quiet`, `--help`, `--confirm`) | -| `GeneralRendererSetup` | General renderer initialization (`--json`, `--yaml`, etc.) | +| `StructuralRendererSetup` | structural renderer initialization (`--json`, `--yaml`, etc.) | ### Dispatcher diff --git a/examples/example-general-renderer/Cargo.lock b/examples/example-general-renderer/Cargo.lock deleted file mode 100644 index 0919b7d..0000000 --- a/examples/example-general-renderer/Cargo.lock +++ /dev/null @@ -1,148 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "example-general-renderer" -version = "0.1.0" -dependencies = [ - "mingling", - "serde", -] - -[[package]] -name = "itoa" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" - -[[package]] -name = "just_fmt" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5454cda0d57db59778608d7a47bff5b16c6705598265869fb052b657f66cf05e" - -[[package]] -name = "memchr" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" - -[[package]] -name = "mingling" -version = "0.2.0" -dependencies = [ - "mingling_core", - "mingling_macros", - "serde", - "size", -] - -[[package]] -name = "mingling_core" -version = "0.2.0" -dependencies = [ - "just_fmt", - "serde", - "serde_json", -] - -[[package]] -name = "mingling_macros" -version = "0.2.0" -dependencies = [ - "just_fmt", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.150" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - -[[package]] -name = "size" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b6709c7b6754dca1311b3c73e79fcce40dd414c782c66d88e8823030093b02b" - -[[package]] -name = "syn" -version = "2.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "zmij" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/examples/example-general-renderer/Cargo.toml b/examples/example-general-renderer/Cargo.toml deleted file mode 100644 index fd7879b..0000000 --- a/examples/example-general-renderer/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "example-general-renderer" -version = "0.1.0" -edition = "2024" - -[dependencies] -serde = { version = "1.0.228", features = ["derive"] } - -[dependencies.mingling] -path = "../../mingling" -features = [ - "general_renderer", - "parser", -] - -[workspace] diff --git a/examples/example-general-renderer/page.toml b/examples/example-general-renderer/page.toml deleted file mode 100644 index 1d3e4b1..0000000 --- a/examples/example-general-renderer/page.toml +++ /dev/null @@ -1,10 +0,0 @@ -[example] -id = "example-general-renderer" -name = "General Renderer" -icon = "📤" -category = "output" -desc = """ -Demonstrates how to render structured output in JSON or YAML using `GeneralRendererSetup` and the `general_renderer` feature. -""" -tags = ["general_renderer", "--json", "--yaml"] -files = ["src/main.rs", "Cargo.toml"] diff --git a/examples/example-general-renderer/src/main.rs b/examples/example-general-renderer/src/main.rs deleted file mode 100644 index 1e02afb..0000000 --- a/examples/example-general-renderer/src/main.rs +++ /dev/null @@ -1,71 +0,0 @@ -//! Example General Renderer -//! -//! > This example demonstrates how to use the `general_renderer` feature to render data into structures such as json / yaml -//! -//! Run -//! ```bash -//! cargo run --manifest-path examples/example-general-renderer/Cargo.toml --quiet -- render Bob 22 -//! cargo run --manifest-path examples/example-general-renderer/Cargo.toml --quiet -- render Bob 22 --json -//! cargo run --manifest-path examples/example-general-renderer/Cargo.toml --quiet -- render Bob 22 --yaml -//! ``` -//! -//! Output: -//! ```plain -//! Bob is 22 years old -//! {"member_name":"Bob","member_age":22} -//! member_name: Bob -//! member_age: 22 -//! ``` - -use mingling::prelude::*; -use mingling::{parser::Picker, setup::GeneralRendererSetup, StructuralData, Groupped}; -use serde::Serialize; - -dispatcher!("render", CMDRender => EntryRender); - -fn main() { - let mut program = ThisProgram::new(); - // Add `GeneralRendererSetup` to receive user input `--json` `--yaml` parameters - program.with_setup(GeneralRendererSetup); - program.with_dispatcher(CMDRender); - let _ = program.exec(); -} - -// --------- IMPORTANT --------- -// For beautiful output structure, do not use `pack!` to wrap the types that need to be output. -// Instead, manually implement -// __________________________________ Mark as structured data so it can be rendered -// / ____________________ Implement serde::Serialize -// | / _________ Implement mingling::Groupped -// | | / to ensure Mingling can recognize the type -// vvvvvvvvvvvv vvvvvvvvv vvvvvvvv -#[derive(StructuralData, Serialize, Groupped)] -struct Info { - #[serde(rename = "member_name")] - name: String, - #[serde(rename = "member_age")] - age: i32, -} -// This will output: {"member_name":"name","member_age":32} structure - -// If using pack!(Info = (String, i32)); -// Output: {"inner":["name", 32]} - -// --------- IMPORTANT --------- - -#[chain] -fn parse_render(prev: EntryRender) -> Next { - let (name, age) = Picker::new(prev.inner) - .pick::(()) - .pick::(()) - .unpack(); - Info { name, age }.to_render() -} - -/// Implement default renderer for when general_renderer is not specified -#[renderer] -fn render_info(prev: Info) { - r_println!("{} is {} years old", prev.name, prev.age); -} - -gen_program!(); diff --git a/examples/example-pack-err/Cargo.toml b/examples/example-pack-err/Cargo.toml index 883fc89..5d61319 100644 --- a/examples/example-pack-err/Cargo.toml +++ b/examples/example-pack-err/Cargo.toml @@ -9,7 +9,7 @@ serde = { version = "1.0.228", features = ["derive"] } [dependencies.mingling] path = "../../mingling" features = [ - "general_renderer", + "structural_renderer", "extra_macros", ] diff --git a/examples/example-pack-err/page.toml b/examples/example-pack-err/page.toml index 255bbdd..37f2c31 100644 --- a/examples/example-pack-err/page.toml +++ b/examples/example-pack-err/page.toml @@ -4,7 +4,7 @@ name = "Pack an Error" icon = "🛑" category = "macros" desc = """ -Demonstrates how to use the `pack_err!` macro to define error types with automatic `name` field (snake_case at compile time) and optional `info` field. Also shows `--json` serialization when `general_renderer` is enabled. +Demonstrates how to use the `pack_err!` macro to define error types with automatic `name` field (snake_case at compile time) and optional `info` field. Also shows `--json` serialization when `structural_renderer` is enabled. """ -tags = ["pack_err!", "extra_macros", "general_renderer", "--json"] +tags = ["pack_err!", "extra_macros", "structural_renderer", "--json"] files = ["src/main.rs", "Cargo.toml"] diff --git a/examples/example-pack-err/src/main.rs b/examples/example-pack-err/src/main.rs index f859fae..8716333 100644 --- a/examples/example-pack-err/src/main.rs +++ b/examples/example-pack-err/src/main.rs @@ -2,7 +2,7 @@ //! //! > This example demonstrates how to use the `pack_err!` macro to define error types //! > with automatic `name` field (set to snake_case at compile time) and optional `info` field. -//! > Also demonstrates `--json` serialization when `general_renderer` is enabled. +//! > Also demonstrates `--json` serialization when `structural_renderer` is enabled. //! //! Run: //! ```bash @@ -27,7 +27,7 @@ //! ``` use mingling::prelude::*; -use mingling::setup::GeneralRendererSetup; +use mingling::setup::StructuralRendererSetup; use std::path::PathBuf; dispatcher!("find", CMDFind => EntryFind); @@ -45,7 +45,7 @@ dispatcher!("find-structural", CMDFindStructural => EntryFindStructural); // The typed form additionally generates `pub fn new(info)`. // name = "error_not_dir" // -// When `general_renderer` is enabled, the struct also gets +// When `structural_renderer` is enabled, the struct also gets // `#[derive(serde::Serialize)]` for --json / --yaml output. // --------- IMPORTANT --------- @@ -132,8 +132,8 @@ gen_program!(); fn main() { let mut program = ThisProgram::new(); - // Add GeneralRendererSetup to support --json / --yaml flags - program.with_setup(GeneralRendererSetup); + // Add StructuralRendererSetup to support --json / --yaml flags + program.with_setup(StructuralRendererSetup); program.with_dispatcher(CMDFind); program.with_dispatcher(CMDFindStructural); let _ = program.exec(); diff --git a/examples/example-structural-renderer/Cargo.lock b/examples/example-structural-renderer/Cargo.lock new file mode 100644 index 0000000..cee5ae3 --- /dev/null +++ b/examples/example-structural-renderer/Cargo.lock @@ -0,0 +1,148 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "example-structural-renderer" +version = "0.1.0" +dependencies = [ + "mingling", + "serde", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "just_fmt" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5454cda0d57db59778608d7a47bff5b16c6705598265869fb052b657f66cf05e" + +[[package]] +name = "memchr" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" + +[[package]] +name = "mingling" +version = "0.2.0" +dependencies = [ + "mingling_core", + "mingling_macros", + "serde", + "size", +] + +[[package]] +name = "mingling_core" +version = "0.2.0" +dependencies = [ + "just_fmt", + "serde", + "serde_json", +] + +[[package]] +name = "mingling_macros" +version = "0.2.0" +dependencies = [ + "just_fmt", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "size" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b6709c7b6754dca1311b3c73e79fcce40dd414c782c66d88e8823030093b02b" + +[[package]] +name = "syn" +version = "2.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/examples/example-structural-renderer/Cargo.toml b/examples/example-structural-renderer/Cargo.toml new file mode 100644 index 0000000..2090166 --- /dev/null +++ b/examples/example-structural-renderer/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "example-structural-renderer" +version = "0.1.0" +edition = "2024" + +[dependencies] +serde = { version = "1.0.228", features = ["derive"] } + +[dependencies.mingling] +path = "../../mingling" +features = [ + "structural_renderer", + "parser", +] + +[workspace] diff --git a/examples/example-structural-renderer/page.toml b/examples/example-structural-renderer/page.toml new file mode 100644 index 0000000..0ed7745 --- /dev/null +++ b/examples/example-structural-renderer/page.toml @@ -0,0 +1,10 @@ +[example] +id = "example-structural-renderer" +name = "structural renderer" +icon = "📤" +category = "output" +desc = """ +Demonstrates how to render structured output in JSON or YAML using `StructuralRendererSetup` and the `structural_renderer` feature. +""" +tags = ["structural_renderer", "--json", "--yaml"] +files = ["src/main.rs", "Cargo.toml"] diff --git a/examples/example-structural-renderer/src/main.rs b/examples/example-structural-renderer/src/main.rs new file mode 100644 index 0000000..21077e7 --- /dev/null +++ b/examples/example-structural-renderer/src/main.rs @@ -0,0 +1,71 @@ +//! Example structural renderer +//! +//! > This example demonstrates how to use the `structural_renderer` feature to render data into structures such as json / yaml +//! +//! Run +//! ```bash +//! cargo run --manifest-path examples/example-structural-renderer/Cargo.toml --quiet -- render Bob 22 +//! cargo run --manifest-path examples/example-structural-renderer/Cargo.toml --quiet -- render Bob 22 --json +//! cargo run --manifest-path examples/example-structural-renderer/Cargo.toml --quiet -- render Bob 22 --yaml +//! ``` +//! +//! Output: +//! ```plain +//! Bob is 22 years old +//! {"member_name":"Bob","member_age":22} +//! member_name: Bob +//! member_age: 22 +//! ``` + +use mingling::prelude::*; +use mingling::{parser::Picker, setup::StructuralRendererSetup, StructuralData, Groupped}; +use serde::Serialize; + +dispatcher!("render", CMDRender => EntryRender); + +fn main() { + let mut program = ThisProgram::new(); + // Add `StructuralRendererSetup` to receive user input `--json` `--yaml` parameters + program.with_setup(StructuralRendererSetup); + program.with_dispatcher(CMDRender); + let _ = program.exec(); +} + +// --------- IMPORTANT --------- +// For beautiful output structure, do not use `pack!` to wrap the types that need to be output. +// Instead, manually implement +// __________________________________ Mark as structured data so it can be rendered +// / ____________________ Implement serde::Serialize +// | / _________ Implement mingling::Groupped +// | | / to ensure Mingling can recognize the type +// vvvvvvvvvvvv vvvvvvvvv vvvvvvvv +#[derive(StructuralData, Serialize, Groupped)] +struct Info { + #[serde(rename = "member_name")] + name: String, + #[serde(rename = "member_age")] + age: i32, +} +// This will output: {"member_name":"name","member_age":32} structure + +// If using pack!(Info = (String, i32)); +// Output: {"inner":["name", 32]} + +// --------- IMPORTANT --------- + +#[chain] +fn parse_render(prev: EntryRender) -> Next { + let (name, age) = Picker::new(prev.inner) + .pick::(()) + .pick::(()) + .unpack(); + Info { name, age }.to_render() +} + +/// Implement default renderer for when structural_renderer is not specified +#[renderer] +fn render_info(prev: Info) { + r_println!("{} is {} years old", prev.name, prev.age); +} + +gen_program!(); diff --git a/examples/full-todolist/Cargo.toml b/examples/full-todolist/Cargo.toml index 50b11a5..e10f0e7 100644 --- a/examples/full-todolist/Cargo.toml +++ b/examples/full-todolist/Cargo.toml @@ -12,7 +12,7 @@ path = "../../mingling" features = [ "parser", "extra_macros", - "general_renderer", + "structural_renderer", ] [workspace] diff --git a/examples/full-todolist/src/main.rs b/examples/full-todolist/src/main.rs index 7f958d4..e4c5aa6 100644 --- a/examples/full-todolist/src/main.rs +++ b/examples/full-todolist/src/main.rs @@ -10,7 +10,7 @@ use mingling::{ macros::route, prelude::*, res::ResExitCode, - setup::{ExitCodeSetup, GeneralRendererSetup, HelpFlagSetup}, + setup::{ExitCodeSetup, StructuralRendererSetup, HelpFlagSetup}, LazyInit, LazyRes, }; @@ -49,7 +49,7 @@ fn main() { // Setups program.with_setup(ExitCodeSetup::default()); - program.with_setup(GeneralRendererSetup); + program.with_setup(StructuralRendererSetup); program.with_setup(HelpFlagSetup::new(["--help", "-h"])); // Flags diff --git a/examples/test-examples.toml b/examples/test-examples.toml index 149f2c6..b4cbb6d 100644 --- a/examples/test-examples.toml +++ b/examples/test-examples.toml @@ -138,12 +138,12 @@ command = "lang-select OCaml" expect.exit-code = 0 expect.result = "Selected: OCaml" -[[test.example-general-renderer]] +[[test.example-structural-renderer]] command = "render Bob 22" expect.exit-code = 0 expect.result = "Bob is 22 years old" -[[test.example-general-renderer]] +[[test.example-structural-renderer]] command = "render Bob 22 --json" expect.exit-code = 0 expect.result = "{\"member_name\":\"Bob\",\"member_age\":22}" diff --git a/mingling/Cargo.toml b/mingling/Cargo.toml index 427bed6..0cb211d 100644 --- a/mingling/Cargo.toml +++ b/mingling/Cargo.toml @@ -15,7 +15,7 @@ serde.workspace = true tokio.workspace = true mingling = { path = ".", features = [ "comp", - "general_renderer", + "structural_renderer", "parser", "repl", ] } @@ -23,7 +23,7 @@ mingling = { path = ".", features = [ [package.metadata.docs.rs] features = [ "builds", - "general_renderer", + "structural_renderer", "repl", "comp", "parser", @@ -45,21 +45,21 @@ repl = ["mingling_core/repl", "mingling_macros/repl"] comp = ["mingling_core/comp", "mingling_macros/comp"] parser = ["dep:size"] -general_renderer = [ - "mingling_core/general_renderer", +structural_renderer = [ + "mingling_core/structural_renderer", "dep:serde", - "mingling_macros/general_renderer", + "mingling_macros/structural_renderer", "json_serde_fmt", ] -general_renderer_empty = [ - "mingling_core/general_renderer", +structural_renderer_empty = [ + "mingling_core/structural_renderer", "dep:serde", - "mingling_macros/general_renderer", + "mingling_macros/structural_renderer", ] -general_renderer_full = [ - "general_renderer", +structural_renderer_full = [ + "structural_renderer", "yaml_serde_fmt", "toml_serde_fmt", "ron_serde_fmt", diff --git a/mingling/src/example_docs.rs b/mingling/src/example_docs.rs index 266a449..c492a11 100644 --- a/mingling/src/example_docs.rs +++ b/mingling/src/example_docs.rs @@ -1170,101 +1170,6 @@ pub mod example_error_handling {} /// gen_program!(); /// ``` pub mod example_exitcode {} -/// Example General Renderer -/// -/// > This example demonstrates how to use the `general_renderer` feature to render data into structures such as json / yaml -/// -/// Run -/// ```bash -/// cargo run --manifest-path examples/example-general-renderer/Cargo.toml --quiet -- render Bob 22 -/// cargo run --manifest-path examples/example-general-renderer/Cargo.toml --quiet -- render Bob 22 --json -/// cargo run --manifest-path examples/example-general-renderer/Cargo.toml --quiet -- render Bob 22 --yaml -/// ``` -/// -/// Output: -/// ```plain -/// Bob is 22 years old -/// {"member_name":"Bob","member_age":22} -/// member_name: Bob -/// member_age: 22 -/// ``` -/// -/// Source code (./Cargo.toml) -/// ```toml -/// [package] -/// name = "example-general-renderer" -/// version = "0.1.0" -/// edition = "2024" -/// -/// [dependencies] -/// serde = { version = "1.0.228", features = ["derive"] } -/// -/// [dependencies.mingling] -/// path = "../../mingling" -/// features = [ -/// "general_renderer", -/// "parser", -/// ] -/// -/// [workspace] -/// ``` -/// -/// Source code (./src/main.rs) -/// ```ignore -/// use mingling::prelude::*; -/// use mingling::{parser::Picker, setup::GeneralRendererSetup, StructuralData, Groupped}; -/// use serde::Serialize; -/// -/// dispatcher!("render", CMDRender => EntryRender); -/// -/// fn main() { -/// let mut program = ThisProgram::new(); -/// // Add `GeneralRendererSetup` to receive user input `--json` `--yaml` parameters -/// program.with_setup(GeneralRendererSetup); -/// program.with_dispatcher(CMDRender); -/// let _ = program.exec(); -/// } -/// -/// // --------- IMPORTANT --------- -/// // For beautiful output structure, do not use `pack!` to wrap the types that need to be output. -/// // Instead, manually implement -/// // __________________________________ Mark as structured data so it can be rendered -/// // / ____________________ Implement serde::Serialize -/// // | / _________ Implement mingling::Groupped -/// // | | / to ensure Mingling can recognize the type -/// // vvvvvvvvvvvv vvvvvvvvv vvvvvvvv -/// #[derive(StructuralData, Serialize, Groupped)] -/// struct Info { -/// #[serde(rename = "member_name")] -/// name: String, -/// #[serde(rename = "member_age")] -/// age: i32, -/// } -/// // This will output: {"member_name":"name","member_age":32} structure -/// -/// // If using pack!(Info = (String, i32)); -/// // Output: {"inner":["name", 32]} -/// -/// // --------- IMPORTANT --------- -/// -/// #[chain] -/// fn parse_render(prev: EntryRender) -> Next { -/// let (name, age) = Picker::new(prev.inner) -/// .pick::(()) -/// .pick::(()) -/// .unpack(); -/// Info { name, age }.to_render() -/// } -/// -/// /// Implement default renderer for when general_renderer is not specified -/// #[renderer] -/// fn render_info(prev: Info) { -/// r_println!("{} is {} years old", prev.name, prev.age); -/// } -/// -/// gen_program!(); -/// ``` -pub mod example_general_renderer {} /// Example Help /// /// > This example demonstrates how to use the `#[help]` macro to generate help information, @@ -1682,7 +1587,7 @@ pub mod example_outside_type {} /// /// > This example demonstrates how to use the `pack_err!` macro to define error types /// > with automatic `name` field (set to snake_case at compile time) and optional `info` field. -/// > Also demonstrates `--json` serialization when `general_renderer` is enabled. +/// > Also demonstrates `--json` serialization when `structural_renderer` is enabled. /// /// Run: /// ```bash @@ -1719,7 +1624,7 @@ pub mod example_outside_type {} /// [dependencies.mingling] /// path = "../../mingling" /// features = [ -/// "general_renderer", +/// "structural_renderer", /// "extra_macros", /// ] /// @@ -1729,7 +1634,7 @@ pub mod example_outside_type {} /// Source code (./src/main.rs) /// ```ignore /// use mingling::prelude::*; -/// use mingling::setup::GeneralRendererSetup; +/// use mingling::setup::StructuralRendererSetup; /// use std::path::PathBuf; /// /// dispatcher!("find", CMDFind => EntryFind); @@ -1747,7 +1652,7 @@ pub mod example_outside_type {} /// // The typed form additionally generates `pub fn new(info)`. /// // name = "error_not_dir" /// // -/// // When `general_renderer` is enabled, the struct also gets +/// // When `structural_renderer` is enabled, the struct also gets /// // `#[derive(serde::Serialize)]` for --json / --yaml output. /// // --------- IMPORTANT --------- /// @@ -1834,8 +1739,8 @@ pub mod example_outside_type {} /// /// fn main() { /// let mut program = ThisProgram::new(); -/// // Add GeneralRendererSetup to support --json / --yaml flags -/// program.with_setup(GeneralRendererSetup); +/// // Add StructuralRendererSetup to support --json / --yaml flags +/// program.with_setup(StructuralRendererSetup); /// program.with_dispatcher(CMDFind); /// program.with_dispatcher(CMDFindStructural); /// let _ = program.exec(); @@ -2256,6 +2161,101 @@ pub mod example_resources {} /// gen_program!(); /// ``` pub mod example_setup {} +/// Example structural renderer +/// +/// > This example demonstrates how to use the `structural_renderer` feature to render data into structures such as json / yaml +/// +/// Run +/// ```bash +/// cargo run --manifest-path examples/example-structural-renderer/Cargo.toml --quiet -- render Bob 22 +/// cargo run --manifest-path examples/example-structural-renderer/Cargo.toml --quiet -- render Bob 22 --json +/// cargo run --manifest-path examples/example-structural-renderer/Cargo.toml --quiet -- render Bob 22 --yaml +/// ``` +/// +/// Output: +/// ```plain +/// Bob is 22 years old +/// {"member_name":"Bob","member_age":22} +/// member_name: Bob +/// member_age: 22 +/// ``` +/// +/// Source code (./Cargo.toml) +/// ```toml +/// [package] +/// name = "example-structural-renderer" +/// version = "0.1.0" +/// edition = "2024" +/// +/// [dependencies] +/// serde = { version = "1.0.228", features = ["derive"] } +/// +/// [dependencies.mingling] +/// path = "../../mingling" +/// features = [ +/// "structural_renderer", +/// "parser", +/// ] +/// +/// [workspace] +/// ``` +/// +/// Source code (./src/main.rs) +/// ```ignore +/// use mingling::prelude::*; +/// use mingling::{parser::Picker, setup::StructuralRendererSetup, StructuralData, Groupped}; +/// use serde::Serialize; +/// +/// dispatcher!("render", CMDRender => EntryRender); +/// +/// fn main() { +/// let mut program = ThisProgram::new(); +/// // Add `StructuralRendererSetup` to receive user input `--json` `--yaml` parameters +/// program.with_setup(StructuralRendererSetup); +/// program.with_dispatcher(CMDRender); +/// let _ = program.exec(); +/// } +/// +/// // --------- IMPORTANT --------- +/// // For beautiful output structure, do not use `pack!` to wrap the types that need to be output. +/// // Instead, manually implement +/// // __________________________________ Mark as structured data so it can be rendered +/// // / ____________________ Implement serde::Serialize +/// // | / _________ Implement mingling::Groupped +/// // | | / to ensure Mingling can recognize the type +/// // vvvvvvvvvvvv vvvvvvvvv vvvvvvvv +/// #[derive(StructuralData, Serialize, Groupped)] +/// struct Info { +/// #[serde(rename = "member_name")] +/// name: String, +/// #[serde(rename = "member_age")] +/// age: i32, +/// } +/// // This will output: {"member_name":"name","member_age":32} structure +/// +/// // If using pack!(Info = (String, i32)); +/// // Output: {"inner":["name", 32]} +/// +/// // --------- IMPORTANT --------- +/// +/// #[chain] +/// fn parse_render(prev: EntryRender) -> Next { +/// let (name, age) = Picker::new(prev.inner) +/// .pick::(()) +/// .pick::(()) +/// .unpack(); +/// Info { name, age }.to_render() +/// } +/// +/// /// Implement default renderer for when structural_renderer is not specified +/// #[renderer] +/// fn render_info(prev: Info) { +/// r_println!("{} is {} years old", prev.name, prev.age); +/// } +/// +/// gen_program!(); +/// ``` +pub mod example_structural_renderer {} /// Example Unit Test /// /// > This example shows how to write unit tests for Chain and Renderer in Mingling diff --git a/mingling/src/features.rs b/mingling/src/features.rs index ec9c7ad..8f147fb 100644 --- a/mingling/src/features.rs +++ b/mingling/src/features.rs @@ -97,39 +97,6 @@ pub const MINGLING_EXTRA_MACROS: bool = false; #[cfg(feature = "extra_macros")] #[allow(unused)] pub const MINGLING_EXTRA_MACROS: bool = true; -/// Whether the `general_renderer` feature is enabled -/// Current: `disabled` -#[cfg(not(feature = "general_renderer"))] -#[allow(unused)] -pub const MINGLING_GENERAL_RENDERER: bool = false; - -/// Whether the `general_renderer` feature is enabled -/// Current: `enabled` -#[cfg(feature = "general_renderer")] -#[allow(unused)] -pub const MINGLING_GENERAL_RENDERER: bool = true; -/// Whether the `general_renderer_empty` feature is enabled -/// Current: `disabled` -#[cfg(not(feature = "general_renderer_empty"))] -#[allow(unused)] -pub const MINGLING_GENERAL_RENDERER_EMPTY: bool = false; - -/// Whether the `general_renderer_empty` feature is enabled -/// Current: `enabled` -#[cfg(feature = "general_renderer_empty")] -#[allow(unused)] -pub const MINGLING_GENERAL_RENDERER_EMPTY: bool = true; -/// Whether the `general_renderer_full` feature is enabled -/// Current: `disabled` -#[cfg(not(feature = "general_renderer_full"))] -#[allow(unused)] -pub const MINGLING_GENERAL_RENDERER_FULL: bool = false; - -/// Whether the `general_renderer_full` feature is enabled -/// Current: `enabled` -#[cfg(feature = "general_renderer_full")] -#[allow(unused)] -pub const MINGLING_GENERAL_RENDERER_FULL: bool = true; /// Whether the `json_serde_fmt` feature is enabled /// Current: `disabled` #[cfg(not(feature = "json_serde_fmt"))] @@ -185,6 +152,39 @@ pub const MINGLING_RON_SERDE_FMT: bool = false; #[cfg(feature = "ron_serde_fmt")] #[allow(unused)] pub const MINGLING_RON_SERDE_FMT: bool = true; +/// Whether the `structural_renderer` feature is enabled +/// Current: `disabled` +#[cfg(not(feature = "structural_renderer"))] +#[allow(unused)] +pub const MINGLING_STRUCTURAL_RENDERER: bool = false; + +/// Whether the `structural_renderer` feature is enabled +/// Current: `enabled` +#[cfg(feature = "structural_renderer")] +#[allow(unused)] +pub const MINGLING_STRUCTURAL_RENDERER: bool = true; +/// Whether the `structural_renderer_empty` feature is enabled +/// Current: `disabled` +#[cfg(not(feature = "structural_renderer_empty"))] +#[allow(unused)] +pub const MINGLING_STRUCTURAL_RENDERER_EMPTY: bool = false; + +/// Whether the `structural_renderer_empty` feature is enabled +/// Current: `enabled` +#[cfg(feature = "structural_renderer_empty")] +#[allow(unused)] +pub const MINGLING_STRUCTURAL_RENDERER_EMPTY: bool = true; +/// Whether the `structural_renderer_full` feature is enabled +/// Current: `disabled` +#[cfg(not(feature = "structural_renderer_full"))] +#[allow(unused)] +pub const MINGLING_STRUCTURAL_RENDERER_FULL: bool = false; + +/// Whether the `structural_renderer_full` feature is enabled +/// Current: `enabled` +#[cfg(feature = "structural_renderer_full")] +#[allow(unused)] +pub const MINGLING_STRUCTURAL_RENDERER_FULL: bool = true; /// Whether the `toml_serde_fmt` feature is enabled /// Current: `disabled` #[cfg(not(feature = "toml_serde_fmt"))] diff --git a/mingling/src/lib.rs b/mingling/src/lib.rs index 4c49f15..b021479 100644 --- a/mingling/src/lib.rs +++ b/mingling/src/lib.rs @@ -97,7 +97,7 @@ pub mod macros { #[cfg(feature = "extra_macros")] pub use mingling_macros::group; /// Like `group!` but also marks the type for structured output - #[cfg(all(feature = "general_renderer", feature = "extra_macros"))] + #[cfg(all(feature = "structural_renderer", feature = "extra_macros"))] pub use mingling_macros::group_structural; /// Used to generate a struct implementing the `HelpRequest` trait via a method pub use mingling_macros::help; @@ -106,13 +106,13 @@ pub mod macros { /// Used to create a wrapper type for use with `Chain` and `Renderer` pub use mingling_macros::pack; /// Like `pack!` but also marks the type for structured output - #[cfg(feature = "general_renderer")] + #[cfg(feature = "structural_renderer")] pub use mingling_macros::pack_structural; /// Used to create an error struct with automatic `name` field #[cfg(feature = "extra_macros")] pub use mingling_macros::pack_err; /// Like `pack_err!` but also marks the type for structured output - #[cfg(all(feature = "general_renderer", feature = "extra_macros"))] + #[cfg(all(feature = "structural_renderer", feature = "extra_macros"))] pub use mingling_macros::pack_err_structural; #[cfg(feature = "comp")] #[doc(hidden)] @@ -158,7 +158,7 @@ pub use mingling_macros::EnumTag; pub use mingling_macros::Groupped; /// derive macro `StructuralData` — marks a type as supporting structured output -#[cfg(feature = "general_renderer")] +#[cfg(feature = "structural_renderer")] pub use mingling_macros::StructuralData; /// Example projects for `Mingling`, for learning how to use `Mingling` @@ -214,13 +214,13 @@ pub mod prelude { /// Re-export of the `pack` macro for creating wrapper types. pub use crate::macros::pack; /// Like `pack!` but also marks the type for structured output - #[cfg(feature = "general_renderer")] + #[cfg(feature = "structural_renderer")] pub use mingling_macros::pack_structural; /// Re-export of the `pack_err` macro for creating error types. #[cfg(feature = "extra_macros")] pub use crate::macros::pack_err; /// Like `pack_err!` but also marks the type for structured output - #[cfg(all(feature = "general_renderer", feature = "extra_macros"))] + #[cfg(all(feature = "structural_renderer", feature = "extra_macros"))] pub use mingling_macros::pack_err_structural; /// Re-export of the `r_print` macro for printing within a renderer context. pub use crate::macros::r_print; diff --git a/mingling/src/setups.rs b/mingling/src/setups.rs index b4fad58..5546268 100644 --- a/mingling/src/setups.rs +++ b/mingling/src/setups.rs @@ -4,11 +4,11 @@ pub use basic::*; mod exit_code; pub use exit_code::*; -#[cfg(feature = "general_renderer")] -mod general_renderer; +#[cfg(feature = "structural_renderer")] +mod structural_renderer; -#[cfg(feature = "general_renderer")] -pub use general_renderer::*; +#[cfg(feature = "structural_renderer")] +pub use structural_renderer::*; #[cfg(feature = "repl")] mod repl_basic; diff --git a/mingling/src/setups/general_renderer.rs b/mingling/src/setups/general_renderer.rs deleted file mode 100644 index 88f5bfa..0000000 --- a/mingling/src/setups/general_renderer.rs +++ /dev/null @@ -1,61 +0,0 @@ -use mingling_core::{Program, ProgramCollect, setup::ProgramSetup}; - -/// Sets up the general renderer for the program: -/// -/// - Adds a `--renderer` global argument to specify the renderer type -pub struct GeneralRendererSimpleSetup; - -impl ProgramSetup for GeneralRendererSimpleSetup -where - C: ProgramCollect, -{ - fn setup(self, program: &mut Program) { - program.global_argument("--renderer", |p, renderer| { - p.general_renderer_name = renderer.into(); - }); - } -} - -/// Sets up the general renderer for the program: -/// -/// - Adds global flags to specify the renderer type: -/// * `--json` for JSON output -/// * `--json-pretty` for pretty-printed JSON output -/// * `--yaml` for YAML output -/// * `--toml` for TOML output -/// * `--ron` for RON output -/// * `--ron-pretty` for pretty-printed RON output -pub struct GeneralRendererSetup; - -impl ProgramSetup for GeneralRendererSetup -where - C: ProgramCollect, -{ - #[allow(unused_variables)] - fn setup(self, program: &mut Program) { - #[cfg(feature = "json_serde_fmt")] - program.global_flag("--json", |p| { - p.general_renderer_name = crate::GeneralRendererSetting::Json; - }); - #[cfg(feature = "json_serde_fmt")] - program.global_flag("--json-pretty", |p| { - p.general_renderer_name = crate::GeneralRendererSetting::JsonPretty; - }); - #[cfg(feature = "yaml_serde_fmt")] - program.global_flag("--yaml", |p| { - p.general_renderer_name = crate::GeneralRendererSetting::Yaml; - }); - #[cfg(feature = "toml_serde_fmt")] - program.global_flag("--toml", |p| { - p.general_renderer_name = crate::GeneralRendererSetting::Toml; - }); - #[cfg(feature = "ron_serde_fmt")] - program.global_flag("--ron", |p| { - p.general_renderer_name = crate::GeneralRendererSetting::Ron; - }); - #[cfg(feature = "ron_serde_fmt")] - program.global_flag("--ron-pretty", |p| { - p.general_renderer_name = crate::GeneralRendererSetting::RonPretty; - }); - } -} diff --git a/mingling/src/setups/structural_renderer.rs b/mingling/src/setups/structural_renderer.rs new file mode 100644 index 0000000..af3ed91 --- /dev/null +++ b/mingling/src/setups/structural_renderer.rs @@ -0,0 +1,61 @@ +use mingling_core::{Program, ProgramCollect, setup::ProgramSetup}; + +/// Sets up the structural renderer for the program: +/// +/// - Adds a `--renderer` global argument to specify the renderer type +pub struct StructuralRendererSimpleSetup; + +impl ProgramSetup for StructuralRendererSimpleSetup +where + C: ProgramCollect, +{ + fn setup(self, program: &mut Program) { + program.global_argument("--renderer", |p, renderer| { + p.structural_renderer_name = renderer.into(); + }); + } +} + +/// Sets up the structural renderer for the program: +/// +/// - Adds global flags to specify the renderer type: +/// * `--json` for JSON output +/// * `--json-pretty` for pretty-printed JSON output +/// * `--yaml` for YAML output +/// * `--toml` for TOML output +/// * `--ron` for RON output +/// * `--ron-pretty` for pretty-printed RON output +pub struct StructuralRendererSetup; + +impl ProgramSetup for StructuralRendererSetup +where + C: ProgramCollect, +{ + #[allow(unused_variables)] + fn setup(self, program: &mut Program) { + #[cfg(feature = "json_serde_fmt")] + program.global_flag("--json", |p| { + p.structural_renderer_name = crate::StructuralRendererSetting::Json; + }); + #[cfg(feature = "json_serde_fmt")] + program.global_flag("--json-pretty", |p| { + p.structural_renderer_name = crate::StructuralRendererSetting::JsonPretty; + }); + #[cfg(feature = "yaml_serde_fmt")] + program.global_flag("--yaml", |p| { + p.structural_renderer_name = crate::StructuralRendererSetting::Yaml; + }); + #[cfg(feature = "toml_serde_fmt")] + program.global_flag("--toml", |p| { + p.structural_renderer_name = crate::StructuralRendererSetting::Toml; + }); + #[cfg(feature = "ron_serde_fmt")] + program.global_flag("--ron", |p| { + p.structural_renderer_name = crate::StructuralRendererSetting::Ron; + }); + #[cfg(feature = "ron_serde_fmt")] + program.global_flag("--ron-pretty", |p| { + p.structural_renderer_name = crate::StructuralRendererSetting::RonPretty; + }); + } +} diff --git a/mingling_core/Cargo.toml b/mingling_core/Cargo.toml index 4ce9ecd..b22a630 100644 --- a/mingling_core/Cargo.toml +++ b/mingling_core/Cargo.toml @@ -17,7 +17,7 @@ async = [] builds = [] dispatch_tree = [] -general_renderer = ["dep:serde"] +structural_renderer = ["dep:serde"] ron_serde_fmt = ["dep:ron"] json_serde_fmt = ["dep:serde_json"] yaml_serde_fmt = ["dep:serde_yaml"] @@ -35,7 +35,7 @@ just_fmt.workspace = true # comp just_template = { workspace = true, optional = true } -# general_renderer +# structural_renderer serde = { workspace = true, optional = true } ron = { workspace = true, optional = true } serde_json = { workspace = true, optional = true } 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 {} diff --git a/mingling_core/tests/test-all/Cargo.toml b/mingling_core/tests/test-all/Cargo.toml index 9eea2de..a63b6e6 100644 --- a/mingling_core/tests/test-all/Cargo.toml +++ b/mingling_core/tests/test-all/Cargo.toml @@ -8,7 +8,7 @@ publish = false [dependencies] mingling = { path = "../../../mingling", features = [ - "general_renderer_full", + "structural_renderer_full", "comp", "builds", "repl", diff --git a/mingling_core/tests/test-all/tests/integration.rs b/mingling_core/tests/test-all/tests/integration.rs index 99910a9..3581702 100644 --- a/mingling_core/tests/test-all/tests/integration.rs +++ b/mingling_core/tests/test-all/tests/integration.rs @@ -1,6 +1,6 @@ use mingling::Flag; -use mingling::GeneralRenderer; -use mingling::GeneralRendererSetting; +use mingling::StructuralRenderer; +use mingling::StructuralRendererSetting; use mingling::MockProgramCollect; use mingling::NextProcess; use mingling::StructuralData; @@ -89,7 +89,7 @@ fn test_render_result_print() { assert_eq!(&*r, "hello"); } -// GeneralRenderer +// StructuralRenderer #[derive(Debug, Clone, PartialEq, Serialize, StructuralData)] struct TestData { @@ -98,25 +98,25 @@ struct TestData { } #[test] -fn test_general_renderer_disable() { +fn test_structural_renderer_disable() { let data = TestData { name: "test".into(), value: 42, }; let mut r = RenderResult::default(); - let result = GeneralRenderer::render(&data, &GeneralRendererSetting::Disable, &mut r); + let result = StructuralRenderer::render(&data, &StructuralRendererSetting::Disable, &mut r); assert!(result.is_ok()); assert!(r.is_empty()); } #[test] -fn test_general_renderer_json() { +fn test_structural_renderer_json() { let data = TestData { name: "test".into(), value: 42, }; let mut r = RenderResult::default(); - let result = GeneralRenderer::render(&data, &GeneralRendererSetting::Json, &mut r); + let result = StructuralRenderer::render(&data, &StructuralRendererSetting::Json, &mut r); assert!(result.is_ok()); assert!(!r.is_empty()); } diff --git a/mingling_core/tests/test-general-renderer/Cargo.lock b/mingling_core/tests/test-general-renderer/Cargo.lock deleted file mode 100644 index 7c4b628..0000000 --- a/mingling_core/tests/test-general-renderer/Cargo.lock +++ /dev/null @@ -1,287 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "bitflags" -version = "2.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" -dependencies = [ - "serde_core", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "hashbrown" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" - -[[package]] -name = "indexmap" -version = "2.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "itoa" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" - -[[package]] -name = "just_fmt" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5454cda0d57db59778608d7a47bff5b16c6705598265869fb052b657f66cf05e" - -[[package]] -name = "memchr" -version = "2.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" - -[[package]] -name = "mingling" -version = "0.2.0" -dependencies = [ - "mingling_core", - "mingling_macros", - "serde", - "size", -] - -[[package]] -name = "mingling_core" -version = "0.2.0" -dependencies = [ - "just_fmt", - "ron", - "serde", - "serde_json", - "serde_yaml", - "toml", -] - -[[package]] -name = "mingling_macros" -version = "0.2.0" -dependencies = [ - "just_fmt", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "once_cell" -version = "1.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "ron" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4147b952f3f819eca0e99527022f7d6a8d05f111aeb0a62960c74eb283bec8fc" -dependencies = [ - "bitflags", - "once_cell", - "serde", - "serde_derive", - "typeid", - "unicode-ident", -] - -[[package]] -name = "ryu" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.150" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - -[[package]] -name = "serde_spanned" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" -dependencies = [ - "serde_core", -] - -[[package]] -name = "serde_yaml" -version = "0.9.34+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" -dependencies = [ - "indexmap", - "itoa", - "ryu", - "serde", - "unsafe-libyaml", -] - -[[package]] -name = "size" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b6709c7b6754dca1311b3c73e79fcce40dd414c782c66d88e8823030093b02b" - -[[package]] -name = "syn" -version = "2.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "test-general-renderer" -version = "0.1.0" -dependencies = [ - "mingling", - "serde", -] - -[[package]] -name = "toml" -version = "1.1.2+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" -dependencies = [ - "indexmap", - "serde_core", - "serde_spanned", - "toml_datetime", - "toml_parser", - "toml_writer", - "winnow", -] - -[[package]] -name = "toml_datetime" -version = "1.1.1+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" -dependencies = [ - "serde_core", -] - -[[package]] -name = "toml_parser" -version = "1.1.2+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" -dependencies = [ - "winnow", -] - -[[package]] -name = "toml_writer" -version = "1.1.1+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" - -[[package]] -name = "typeid" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "unsafe-libyaml" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" - -[[package]] -name = "winnow" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" - -[[package]] -name = "zmij" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/mingling_core/tests/test-general-renderer/Cargo.toml b/mingling_core/tests/test-general-renderer/Cargo.toml deleted file mode 100644 index 3d038aa..0000000 --- a/mingling_core/tests/test-general-renderer/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "test-general-renderer" -version = "0.1.0" -edition = "2024" -publish = false - -[workspace] - -[dependencies] -mingling = { path = "../../../mingling", features = ["general_renderer_full", "parser"] } -serde = { version = "1", features = ["derive"] } diff --git a/mingling_core/tests/test-general-renderer/tests/integration.rs b/mingling_core/tests/test-general-renderer/tests/integration.rs deleted file mode 100644 index 2e2472e..0000000 --- a/mingling_core/tests/test-general-renderer/tests/integration.rs +++ /dev/null @@ -1,75 +0,0 @@ -use mingling::{GeneralRenderer, GeneralRendererSetting, RenderResult, StructuralData}; -use serde::Serialize; - -#[derive(Debug, Clone, PartialEq, Serialize, StructuralData)] -struct TestData { - name: String, - value: i32, -} - -fn test_data() -> TestData { - TestData { - name: "test".into(), - value: 42, - } -} - -#[test] -fn test_render_disable() { - let mut r = RenderResult::default(); - let result = GeneralRenderer::render(&test_data(), &GeneralRendererSetting::Disable, &mut r); - assert!(result.is_ok()); - assert!(r.is_empty()); -} - -#[test] -fn test_render_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("\"test\"")); - assert!(output.contains("\"value\"")); - assert!(output.contains("42")); -} - -#[test] -fn test_render_yaml() { - let mut r = RenderResult::default(); - let result = GeneralRenderer::render(&test_data(), &GeneralRendererSetting::Yaml, &mut r); - assert!(result.is_ok()); - assert!(!r.is_empty()); - let output: String = r.into(); - assert!(output.contains("name:")); - assert!(output.contains("test")); - assert!(output.contains("value:")); - assert!(output.contains("42")); -} - -#[test] -fn test_render_toml() { - let mut r = RenderResult::default(); - let result = GeneralRenderer::render(&test_data(), &GeneralRendererSetting::Toml, &mut r); - assert!(result.is_ok()); - assert!(!r.is_empty()); - let output: String = r.into(); - assert!(output.contains("name = ")); - assert!(output.contains("test")); - assert!(output.contains("value = ")); - assert!(output.contains("42")); -} - -#[test] -fn test_render_ron() { - let mut r = RenderResult::default(); - let result = GeneralRenderer::render(&test_data(), &GeneralRendererSetting::Ron, &mut r); - assert!(result.is_ok()); - assert!(!r.is_empty()); - let output: String = r.into(); - assert!(output.contains("name:")); - assert!(output.contains("\"test\"")); - assert!(output.contains("value:")); - assert!(output.contains("42")); -} diff --git a/mingling_core/tests/test-structural-renderer/Cargo.lock b/mingling_core/tests/test-structural-renderer/Cargo.lock new file mode 100644 index 0000000..a0f7088 --- /dev/null +++ b/mingling_core/tests/test-structural-renderer/Cargo.lock @@ -0,0 +1,287 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "bitflags" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" +dependencies = [ + "serde_core", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "just_fmt" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5454cda0d57db59778608d7a47bff5b16c6705598265869fb052b657f66cf05e" + +[[package]] +name = "memchr" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" + +[[package]] +name = "mingling" +version = "0.2.0" +dependencies = [ + "mingling_core", + "mingling_macros", + "serde", + "size", +] + +[[package]] +name = "mingling_core" +version = "0.2.0" +dependencies = [ + "just_fmt", + "ron", + "serde", + "serde_json", + "serde_yaml", + "toml", +] + +[[package]] +name = "mingling_macros" +version = "0.2.0" +dependencies = [ + "just_fmt", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ron" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4147b952f3f819eca0e99527022f7d6a8d05f111aeb0a62960c74eb283bec8fc" +dependencies = [ + "bitflags", + "once_cell", + "serde", + "serde_derive", + "typeid", + "unicode-ident", +] + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "size" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b6709c7b6754dca1311b3c73e79fcce40dd414c782c66d88e8823030093b02b" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "test-structural-renderer" +version = "0.1.0" +dependencies = [ + "mingling", + "serde", +] + +[[package]] +name = "toml" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "winnow" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/mingling_core/tests/test-structural-renderer/Cargo.toml b/mingling_core/tests/test-structural-renderer/Cargo.toml new file mode 100644 index 0000000..6ae8fce --- /dev/null +++ b/mingling_core/tests/test-structural-renderer/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "test-structural-renderer" +version = "0.1.0" +edition = "2024" +publish = false + +[workspace] + +[dependencies] +mingling = { path = "../../../mingling", features = ["structural_renderer_full", "parser"] } +serde = { version = "1", features = ["derive"] } diff --git a/mingling_core/tests/test-structural-renderer/tests/integration.rs b/mingling_core/tests/test-structural-renderer/tests/integration.rs new file mode 100644 index 0000000..3c3c6db --- /dev/null +++ b/mingling_core/tests/test-structural-renderer/tests/integration.rs @@ -0,0 +1,75 @@ +use mingling::{StructuralRenderer, StructuralRendererSetting, RenderResult, StructuralData}; +use serde::Serialize; + +#[derive(Debug, Clone, PartialEq, Serialize, StructuralData)] +struct TestData { + name: String, + value: i32, +} + +fn test_data() -> TestData { + TestData { + name: "test".into(), + value: 42, + } +} + +#[test] +fn test_render_disable() { + let mut r = RenderResult::default(); + let result = StructuralRenderer::render(&test_data(), &StructuralRendererSetting::Disable, &mut r); + assert!(result.is_ok()); + assert!(r.is_empty()); +} + +#[test] +fn test_render_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("\"test\"")); + assert!(output.contains("\"value\"")); + assert!(output.contains("42")); +} + +#[test] +fn test_render_yaml() { + let mut r = RenderResult::default(); + let result = StructuralRenderer::render(&test_data(), &StructuralRendererSetting::Yaml, &mut r); + assert!(result.is_ok()); + assert!(!r.is_empty()); + let output: String = r.into(); + assert!(output.contains("name:")); + assert!(output.contains("test")); + assert!(output.contains("value:")); + assert!(output.contains("42")); +} + +#[test] +fn test_render_toml() { + let mut r = RenderResult::default(); + let result = StructuralRenderer::render(&test_data(), &StructuralRendererSetting::Toml, &mut r); + assert!(result.is_ok()); + assert!(!r.is_empty()); + let output: String = r.into(); + assert!(output.contains("name = ")); + assert!(output.contains("test")); + assert!(output.contains("value = ")); + assert!(output.contains("42")); +} + +#[test] +fn test_render_ron() { + let mut r = RenderResult::default(); + let result = StructuralRenderer::render(&test_data(), &StructuralRendererSetting::Ron, &mut r); + assert!(result.is_ok()); + assert!(!r.is_empty()); + let output: String = r.into(); + assert!(output.contains("name:")); + assert!(output.contains("\"test\"")); + assert!(output.contains("value:")); + assert!(output.contains("42")); +} diff --git a/mingling_macros/Cargo.toml b/mingling_macros/Cargo.toml index a5fdabf..db65381 100644 --- a/mingling_macros/Cargo.toml +++ b/mingling_macros/Cargo.toml @@ -21,7 +21,7 @@ async = [] clap = [] comp = [] dispatch_tree = [] -general_renderer = [] +structural_renderer = [] repl = [] extra_macros = [] diff --git a/mingling_macros/src/groupped.rs b/mingling_macros/src/groupped.rs index 1459522..8aee003 100644 --- a/mingling_macros/src/groupped.rs +++ b/mingling_macros/src/groupped.rs @@ -28,7 +28,7 @@ pub fn derive_groupped(input: TokenStream) -> TokenStream { expanded.into() } -#[cfg(feature = "general_renderer")] +#[cfg(feature = "structural_renderer")] pub fn derive_groupped_serialize(input: TokenStream) -> TokenStream { // Parse the input struct/enum let input_parsed = parse_macro_input!(input as DeriveInput); diff --git a/mingling_macros/src/lib.rs b/mingling_macros/src/lib.rs index 27bb80c..ad3b6a9 100644 --- a/mingling_macros/src/lib.rs +++ b/mingling_macros/src/lib.rs @@ -99,7 +99,7 @@ //! | `comp` | [`#[completion]`](attr.completion.html), [`suggest!`], [`suggest_enum!`] | //! | `extra_macros` | [`entry!`], [`empty_result!`], [`route!`], [`#[program_setup]`](attr.program_setup.html) | //! | `dispatch_tree` | `register_dispatcher!` (enables trie-based command dispatch) | -//! | `general_renderer` | Enables JSON/YAML/TOML/RON serialization renderers | +//! | `structural_renderer` | Enables JSON/YAML/TOML/RON serialization renderers | //! | `async` | Enables async `#[chain]` functions | //! | `repl` | Enables REPL execution loop | //! @@ -156,7 +156,7 @@ mod enum_tag; mod group_impl; mod groupped; mod help; -#[cfg(feature = "general_renderer")] +#[cfg(feature = "structural_renderer")] mod structural_data; mod node; mod pack; @@ -182,12 +182,12 @@ pub(crate) fn get_global_set(lock: &OnceLock>>) -> &Mutex pub(crate) type Registry = OnceLock>>; // Global variables -#[cfg(feature = "general_renderer")] -pub(crate) static GENERAL_RENDERERS: Registry = OnceLock::new(); +#[cfg(feature = "structural_renderer")] +pub(crate) static STRUCTURAL_RENDERERS: Registry = OnceLock::new(); /// Types explicitly marked with `#[derive(StructuralData)]` or created via /// `pack_structural!` / `group_structural!`. -#[cfg(feature = "general_renderer")] +#[cfg(feature = "structural_renderer")] pub(crate) static STRUCTURED_TYPES: Registry = OnceLock::new(); #[cfg(feature = "comp")] @@ -293,8 +293,8 @@ pub fn group(input: TokenStream) -> TokenStream { /// group_structural!(IoError = std::io::Error); /// ``` /// -/// Requires the `general_renderer` and `extra_macros` features. -#[cfg(all(feature = "general_renderer", feature = "extra_macros"))] +/// Requires the `structural_renderer` and `extra_macros` features. +#[cfg(all(feature = "structural_renderer", feature = "extra_macros"))] #[proc_macro] pub fn group_structural(input: TokenStream) -> TokenStream { structural_data::group_structural(input) @@ -384,7 +384,7 @@ pub fn node(input: TokenStream) -> TokenStream { /// The struct is also registered via `register_type!` so that `gen_program!` /// can include it in the program enum. /// -/// When the `general_renderer` feature is enabled, the struct also gets +/// When the `structural_renderer` feature is enabled, the struct also gets /// `#[derive(serde::Serialize)]`. #[proc_macro] pub fn pack(input: TokenStream) -> TokenStream { @@ -406,8 +406,8 @@ pub fn pack(input: TokenStream) -> TokenStream { /// impl ::mingling::StructuralData for Info {} /// ``` /// -/// Requires the `general_renderer` feature. -#[cfg(feature = "general_renderer")] +/// Requires the `structural_renderer` feature. +#[cfg(feature = "structural_renderer")] #[proc_macro] pub fn pack_structural(input: TokenStream) -> TokenStream { structural_data::pack_structural(input) @@ -471,7 +471,7 @@ pub fn pack_structural(input: TokenStream) -> TokenStream { /// } /// ``` /// -/// When the `general_renderer` feature is enabled, the struct also gets +/// When the `structural_renderer` feature is enabled, the struct also gets /// `#[derive(serde::Serialize)]`. /// /// This macro is only available with the `extra_macros` feature. @@ -491,8 +491,8 @@ pub fn pack_err(input: TokenStream) -> TokenStream { /// pack_err_structural!(ErrorNotDir = PathBuf); /// ``` /// -/// Requires the `general_renderer` and `extra_macros` features. -#[cfg(all(feature = "general_renderer", feature = "extra_macros"))] +/// Requires the `structural_renderer` and `extra_macros` features. +#[cfg(all(feature = "structural_renderer", feature = "extra_macros"))] #[proc_macro] pub fn pack_err_structural(input: TokenStream) -> TokenStream { pack_err::pack_err_structural(input) @@ -685,7 +685,7 @@ pub fn dispatcher(input: TokenStream) -> TokenStream { /// Unlike `print!`, this macro writes to the in-memory `RenderResult` buffer /// rather than directly to stdout. The buffered output is flushed automatically /// when the renderer returns, allowing the framework to control output timing -/// and capture (e.g., for testing or general rendering to JSON/YAML). +/// and capture (e.g., for testing or structural rendering to JSON/YAML). /// /// This macro requires a mutable reference to a [`RenderResult`] named /// `__renderer_inner_result` to be in scope, which is automatically provided @@ -1068,7 +1068,7 @@ pub fn completion(attr: TokenStream, item: TokenStream) -> TokenStream { /// /// #[program_setup] /// fn configure(program: &mut Program) { -/// program.with_setup(GeneralRendererSetup); +/// program.with_setup(StructuralRendererSetup); /// program.user_context.some_flag = true; /// } /// ``` @@ -1387,7 +1387,7 @@ pub fn derive_enum_tag(input: TokenStream) -> TokenStream { /// age: i32, /// } /// ``` -#[cfg(feature = "general_renderer")] +#[cfg(feature = "structural_renderer")] #[proc_macro_derive(StructuralData)] pub fn derive_structural_data(input: TokenStream) -> TokenStream { structural_data::derive_structural_data(input) @@ -1395,10 +1395,10 @@ pub fn derive_structural_data(input: TokenStream) -> TokenStream { /// Derive macro for implementing both `Groupped` and `serde::Serialize` on a struct. /// -/// **This macro is only available with the `general_renderer` feature.** +/// **This macro is only available with the `structural_renderer` feature.** /// /// This is identical to `#[derive(Groupped)]` but also adds `#[derive(serde::Serialize)]` -/// to the struct, which is required for the general renderer to serialize output +/// to the struct, which is required for the structural renderer to serialize output /// to formats like JSON, YAML, TOML, or RON. /// /// # Syntax @@ -1423,7 +1423,7 @@ pub fn derive_structural_data(input: TokenStream) -> TokenStream { /// age: i32, /// } /// ``` -#[cfg(feature = "general_renderer")] +#[cfg(feature = "structural_renderer")] #[proc_macro_derive(GrouppedSerialize, attributes(group))] pub fn derive_groupped_serialize(input: TokenStream) -> TokenStream { groupped::derive_groupped_serialize(input) @@ -1638,8 +1638,8 @@ pub fn register_chain(input: TokenStream) -> TokenStream { /// /// This macro is called internally by `#[renderer]`(macro.renderer.html) and is /// generally not needed in user code. It inserts entries into the global -/// `RENDERERS`, `RENDERERS_EXIST` and (with `general_renderer` feature) -/// `GENERAL_RENDERERS` registries. +/// `RENDERERS`, `RENDERERS_EXIST` and (with `structural_renderer` feature) +/// `STRUCTURAL_RENDERERS` registries. /// /// # Syntax /// @@ -1704,7 +1704,7 @@ pub fn program_fallback_gen(_input: TokenStream) -> TokenStream { /// creates an enum with each type as a variant. /// 2. Generates the `Display` implementation for the enum. /// 3. Generates the `ProgramCollect` implementation that dispatches to all -/// registered renderers, chains, help handlers, completions, and general renderers. +/// registered renderers, chains, help handlers, completions, and structural renderers. /// 4. Adds a `new()` constructor on the enum returning `Program`. /// /// The generated enum's representation type (`#[repr(u8)]`, `#[repr(u16)]`, etc.) @@ -1738,7 +1738,7 @@ pub fn program_fallback_gen(_input: TokenStream) -> TokenStream { /// fn has_renderer(any) -> bool { /* checks renderer registry */ } /// fn has_chain(any) -> bool { /* checks chain registry */ } /// // (with comp feature) fn do_comp(...) -/// // (with general_renderer feature) fn general_render(...) +/// // (with structural_renderer feature) fn structural_render(...) /// } /// /// impl MyProgram { @@ -1781,8 +1781,8 @@ pub fn program_final_gen(_input: TokenStream) -> TokenStream { let renderer_exist = get_global_set(&RENDERERS_EXIST).lock().unwrap().clone(); let chain_exist = get_global_set(&CHAINS_EXIST).lock().unwrap().clone(); - #[cfg(feature = "general_renderer")] - let general_renderers = get_global_set(&GENERAL_RENDERERS).lock().unwrap().clone(); + #[cfg(feature = "structural_renderer")] + let structural_renderers = get_global_set(&STRUCTURAL_RENDERERS).lock().unwrap().clone(); #[cfg(feature = "comp")] let completions = get_global_set(&COMPLETIONS).lock().unwrap().clone(); @@ -1812,27 +1812,27 @@ pub fn program_final_gen(_input: TokenStream) -> TokenStream { .map(|s| syn::parse_str::(s).unwrap()) .collect(); - #[cfg(feature = "general_renderer")] - let general_renderer_tokens: Vec = general_renderers + #[cfg(feature = "structural_renderer")] + let structural_renderer_tokens: Vec = structural_renderers .iter() .map(|s| syn::parse_str::(s).unwrap()) .collect(); - #[cfg(feature = "general_renderer")] - let general_render = quote! { - fn general_render( + #[cfg(feature = "structural_renderer")] + let structural_render = quote! { + fn structural_render( any: ::mingling::AnyOutput, - setting: &::mingling::GeneralRendererSetting, - ) -> Result<::mingling::RenderResult, ::mingling::error::GeneralRendererSerializeError> { + setting: &::mingling::StructuralRendererSetting, + ) -> Result<::mingling::RenderResult, ::mingling::error::StructuralRendererSerializeError> { match any.member_id { - #(#general_renderer_tokens)* + #(#structural_renderer_tokens)* _ => Ok(::mingling::RenderResult::default()), } } }; - #[cfg(not(feature = "general_renderer"))] - let general_render = quote! {}; + #[cfg(not(feature = "structural_renderer"))] + let structural_render = quote! {}; #[cfg(feature = "dispatch_tree")] let compile_time_dispatchers: Vec = get_global_set(&COMPILE_TIME_DISPATCHERS) @@ -2048,7 +2048,7 @@ pub fn program_final_gen(_input: TokenStream) -> TokenStream { } } #dispatch_tree_nodes - #general_render + #structural_render #comp } @@ -2079,8 +2079,8 @@ pub fn program_final_gen(_input: TokenStream) -> TokenStream { .lock() .unwrap() .clear(); - #[cfg(feature = "general_renderer")] - get_global_set(&GENERAL_RENDERERS).lock().unwrap().clear(); + #[cfg(feature = "structural_renderer")] + get_global_set(&STRUCTURAL_RENDERERS).lock().unwrap().clear(); TokenStream::from(expanded) } diff --git a/mingling_macros/src/pack.rs b/mingling_macros/src/pack.rs index 5a6ccb0..7f05232 100644 --- a/mingling_macros/src/pack.rs +++ b/mingling_macros/src/pack.rs @@ -34,7 +34,7 @@ pub fn pack(input: TokenStream) -> TokenStream { let attrs = pack_input.attrs; // Generate the struct definition - // Note: No longer derives Serialize under general_renderer. + // Note: No longer derives Serialize under structural_renderer. // Use pack_structual! for structured output support. let struct_def = quote! { #(#attrs)* diff --git a/mingling_macros/src/pack_err.rs b/mingling_macros/src/pack_err.rs index 8f147be..3e258b2 100644 --- a/mingling_macros/src/pack_err.rs +++ b/mingling_macros/src/pack_err.rs @@ -69,7 +69,7 @@ pub fn pack_err(input: TokenStream) -> TokenStream { let name_str = type_name.to_string(); let snake_name = to_snake_case(&name_str); - // Note: No longer derives Serialize under general_renderer. + // Note: No longer derives Serialize under structural_renderer. // Use pack_err_structural for structured output support. let derive = quote! { #[derive(::mingling::Groupped)] @@ -102,7 +102,7 @@ pub fn pack_err(input: TokenStream) -> TokenStream { let name_str = type_name.to_string(); let snake_name = to_snake_case(&name_str); - // Note: No longer derives Serialize under general_renderer. + // Note: No longer derives Serialize under structural_renderer. // Use pack_err_structural for structured output support. let derive = quote! { #[derive(::mingling::Groupped)] @@ -152,7 +152,7 @@ pub fn pack_err(input: TokenStream) -> TokenStream { /// impl ::mingling::__private::StructuralDataSealed for ErrorNotFound {} /// impl ::mingling::__private::StructuralData for ErrorNotFound {} /// ``` -#[cfg(feature = "general_renderer")] +#[cfg(feature = "structural_renderer")] pub fn pack_err_structural(input: TokenStream) -> TokenStream { let parsed = parse_macro_input!(input as PackErrInput); diff --git a/mingling_macros/src/renderer.rs b/mingling_macros/src/renderer.rs index 6de3d59..880c50f 100644 --- a/mingling_macros/src/renderer.rs +++ b/mingling_macros/src/renderer.rs @@ -183,9 +183,9 @@ pub fn build_renderer_exist_entry(previous_type: &TypePath) -> proc_macro2::Toke } } -/// Builds the general renderer entry -#[cfg(feature = "general_renderer")] -pub fn build_general_renderer_entry(previous_type: &TypePath) -> proc_macro2::TokenStream { +/// Builds the structural renderer entry +#[cfg(feature = "structural_renderer")] +pub fn build_structural_renderer_entry(previous_type: &TypePath) -> proc_macro2::TokenStream { let enum_variant = &previous_type.path.segments.last().unwrap().ident; quote! { Self::#enum_variant => { @@ -193,7 +193,7 @@ pub fn build_general_renderer_entry(previous_type: &TypePath) -> proc_macro2::To // and `AnyOutput::new` ensures the type implements serde::Serialize let raw = unsafe { any.restore::<#previous_type>().unwrap_unchecked() }; let mut __renderer_inner_result = ::mingling::RenderResult::default(); - ::mingling::GeneralRenderer::render(&raw, setting, &mut __renderer_inner_result)?; + ::mingling::StructuralRenderer::render(&raw, setting, &mut __renderer_inner_result)?; Ok(__renderer_inner_result) } } @@ -231,14 +231,14 @@ pub fn register_renderer(input: TokenStream) -> TokenStream { // Register the renderer in the global list let renderer_entry = build_renderer_entry(&struct_name, &previous_type); let renderer_exist_entry = build_renderer_exist_entry(&previous_type); - #[cfg(feature = "general_renderer")] - let general_renderer_entry = build_general_renderer_entry(&previous_type); + #[cfg(feature = "structural_renderer")] + let structural_renderer_entry = build_structural_renderer_entry(&previous_type); let renderer_entry_str = renderer_entry.to_string(); let renderer_exist_entry_str = renderer_exist_entry.to_string(); - #[cfg(feature = "general_renderer")] - let general_renderer_entry_str = general_renderer_entry.to_string(); + #[cfg(feature = "structural_renderer")] + let structural_renderer_entry_str = structural_renderer_entry.to_string(); // Check for duplicate variant before acquiring other locks let variant_name = previous_type @@ -264,21 +264,21 @@ pub fn register_renderer(input: TokenStream) -> TokenStream { let mut renderers = get_global_set(&crate::RENDERERS).lock().unwrap(); let mut renderer_exist = get_global_set(&crate::RENDERERS_EXIST).lock().unwrap(); - #[cfg(feature = "general_renderer")] - let mut general_renderers = get_global_set(&crate::GENERAL_RENDERERS).lock().unwrap(); + #[cfg(feature = "structural_renderer")] + let mut structural_renderers = get_global_set(&crate::STRUCTURAL_RENDERERS).lock().unwrap(); renderers.insert(renderer_entry_str); renderer_exist.insert(renderer_exist_entry_str); - // Only register general renderer if the type is in STRUCTURED_TYPES - #[cfg(feature = "general_renderer")] + // Only register structural renderer if the type is in STRUCTURED_TYPES + #[cfg(feature = "structural_renderer")] { let is_structured = get_global_set(&crate::STRUCTURED_TYPES) .lock() .unwrap() .contains(&variant_name); if is_structured { - general_renderers.insert(general_renderer_entry_str); + structural_renderers.insert(structural_renderer_entry_str); } } diff --git a/mingling_macros/src/structural_data.rs b/mingling_macros/src/structural_data.rs index 593b52d..37fee0f 100644 --- a/mingling_macros/src/structural_data.rs +++ b/mingling_macros/src/structural_data.rs @@ -13,7 +13,7 @@ use crate::get_global_set; /// will fail to compile if `Serialize` is not in scope or implemented. /// /// Also registers the type name in the global `STRUCTURED_TYPES` registry so that -/// the `general_render` match arm is generated by `gen_program!()`. +/// the `structural_render` match arm is generated by `gen_program!()`. pub(crate) fn derive_structural_data(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let type_name = input.ident; @@ -65,8 +65,8 @@ pub(crate) fn pack_structural(input: TokenStream) -> TokenStream { .unwrap() .insert(type_name_str); - // Struct definition (with Serialize derive, same as pack! under general_renderer) - #[cfg(not(feature = "general_renderer"))] + // Struct definition (with Serialize derive, same as pack! under structural_renderer) + #[cfg(not(feature = "structural_renderer"))] let struct_def = quote! { #(#attrs)* pub struct #type_name { @@ -74,7 +74,7 @@ pub(crate) fn pack_structural(input: TokenStream) -> TokenStream { } }; - #[cfg(feature = "general_renderer")] + #[cfg(feature = "structural_renderer")] let struct_def = quote! { #(#attrs)* #[derive(serde::Serialize)] diff --git a/mling/Cargo.toml b/mling/Cargo.toml index e73fe02..4954320 100644 --- a/mling/Cargo.toml +++ b/mling/Cargo.toml @@ -22,7 +22,7 @@ path = "src/bin/mling.rs" mingling = { path = "../mingling", features = [ "parser", "comp", - "general_renderer", + "structural_renderer", "extra_macros", "yaml_serde_fmt", ] } diff --git a/mling/src/cli.rs b/mling/src/cli.rs index a6d099b..01a836a 100644 --- a/mling/src/cli.rs +++ b/mling/src/cli.rs @@ -12,7 +12,7 @@ use mingling::{ hook::ProgramHook, macros::{chain, help, pack, program_setup, r_println, renderer}, res::ResExitCode, - setup::{ExitCodeSetup, GeneralRendererSetup, HelpFlagSetup, QuietFlagSetup}, + setup::{ExitCodeSetup, StructuralRendererSetup, HelpFlagSetup, QuietFlagSetup}, }; use std::{env::current_dir, path::PathBuf, process::exit, str::FromStr}; @@ -58,7 +58,7 @@ pub fn run() { // Setups program.with_setup(HelpFlagSetup::new(["-h", "--help"])); - program.with_setup(GeneralRendererSetup); + program.with_setup(StructuralRendererSetup); program.with_setup(ExitCodeSetup::default()); program.with_setup(StandardOutputSetup); -- cgit