diff options
Diffstat (limited to 'mingling_core/src')
| -rw-r--r-- | mingling_core/src/any.rs | 128 | ||||
| -rw-r--r-- | mingling_core/src/any/group.rs | 12 | ||||
| -rw-r--r-- | mingling_core/src/asset.rs | 35 | ||||
| -rw-r--r-- | mingling_core/src/asset/global_resource.rs | 5 | ||||
| -rw-r--r-- | mingling_core/src/build.rs | 13 | ||||
| -rw-r--r-- | mingling_core/src/build/comp.rs (renamed from mingling_core/src/builds/comp.rs) | 0 | ||||
| -rw-r--r-- | mingling_core/src/build/pathf.rs (renamed from mingling_core/src/builds/pathf.rs) | 0 | ||||
| -rw-r--r-- | mingling_core/src/builds.rs | 7 | ||||
| -rw-r--r-- | mingling_core/src/lib.rs | 120 | ||||
| -rw-r--r-- | mingling_core/src/private.rs | 12 | ||||
| -rw-r--r-- | mingling_core/src/program/collection/mock.rs | 7 | ||||
| -rw-r--r-- | mingling_core/src/program/hook.rs | 12 | ||||
| -rw-r--r-- | mingling_core/src/renderer/render_result.rs | 2 |
13 files changed, 242 insertions, 111 deletions
diff --git a/mingling_core/src/any.rs b/mingling_core/src/any.rs index ec29a1b..e922e2e 100644 --- a/mingling_core/src/any.rs +++ b/mingling_core/src/any.rs @@ -1,8 +1,8 @@ +use crate::ProgramCollect; use crate::error::ChainProcessError; -use crate::{Grouped, ProgramCollect}; -#[doc(hidden)] -pub mod group; +mod group; +pub use group::*; /// Any type output /// @@ -22,14 +22,14 @@ pub struct AnyOutput<G> { /// /// This is set during construction and used for type-checking /// in downcast, restore, and is methods. - pub type_id: std::any::TypeId, + pub(crate) type_id: std::any::TypeId, /// The variant identifier returned by [`Grouped::member_id`] for the /// concrete type stored in `inner`. /// /// This is used by the scheduler to dispatch on the correct enum /// variant when routing the output. - pub member_id: G, + pub(crate) member_id: G, } impl<G> AnyOutput<G> { @@ -45,6 +45,52 @@ impl<G> AnyOutput<G> { } } + /// Create an `AnyOutput` from a raw value with a manually specified member_id. + /// + /// This function bypasses the [`Grouped`] trait, meaning the `member_id` you provide + /// does **not** have to match the actual concrete type `T`. The scheduler uses + /// `member_id` to determine which enum variant the output belongs to, and later + /// attempts to restore the value to the concrete type `T` based on that variant. + /// + /// # Safety + /// + /// - The caller must ensure that `member_id` correctly corresponds to the concrete + /// type `T` according to the scheduling logic. If `member_id` does not match, + /// calling [`restore`](Self::restore) or [`downcast`](Self::downcast) with the + /// type associated with `member_id` will cause **undefined behavior**. + /// - This safety contract is the caller's responsibility; the compiler cannot + /// enforce the correspondence between `member_id` and the stored type. + pub unsafe fn new_bare<T>(value: T, member_id: G) -> Self + where + T: Send + 'static, + { + Self { + inner: Box::new(value), + type_id: std::any::TypeId::of::<T>(), + member_id, + } + } + + /// Get the [`TypeId`] of the concrete type stored in `inner`. + /// + /// The `TypeId` is set during construction (via [`AnyOutput::new`] or [`AnyOutput::new_bare`]) + /// and is used for subsequent downcasting and type checking. + pub fn type_id(&self) -> std::any::TypeId { + self.type_id + } + + /// Get the [`member_id`] of the concrete type stored in `inner`. + /// + /// [`member_id`] is set during construction (via [`AnyOutput::new`] or [`AnyOutput::new_bare`]) + /// and identifies which variant of the output enum this value corresponds to. + /// The scheduler uses this value to dispatch the output to the correct next step. + pub fn member_id(&self) -> G + where + G: Copy, + { + self.member_id + } + /// Attempt to downcast the `AnyOutput` to a concrete type. /// /// # Errors @@ -190,7 +236,17 @@ mod tests { value: i32, } - impl Grouped<MockGroup> for AlphaData { + /// # Safety + /// + /// This implementation is only for testing purposes to satisfy trait bounds. + /// Since this code only constructs `AnyOutput` and calls methods like + /// `downcast`, `is`, `restore`, `route_chain`, and `route_renderer` — + /// none of which involve `ProgramCollect::do_chain` or + /// `ProgramCollect::render` — the type/member_id correspondence is + /// never exploited in an unsafe way here. + /// The caller must ensure that the associated `member_id` correctly + /// corresponds to the type's role in the group. + unsafe impl Grouped<MockGroup> for AlphaData { fn member_id() -> MockGroup { MockGroup::Alpha } @@ -202,7 +258,17 @@ mod tests { name: String, } - impl Grouped<MockGroup> for BetaData { + /// # Safety + /// + /// This implementation is only for testing purposes to satisfy trait bounds. + /// Since this code only constructs `AnyOutput` and calls methods like + /// `downcast`, `is`, `restore`, `route_chain`, and `route_renderer` — + /// none of which involve `ProgramCollect::do_chain` or + /// `ProgramCollect::render` — the type/member_id correspondence is + /// never exploited in an unsafe way here. + /// The caller must ensure that the associated `member_id` correctly + /// corresponds to the type's role in the group. + unsafe impl Grouped<MockGroup> for BetaData { fn member_id() -> MockGroup { MockGroup::Beta } @@ -213,7 +279,17 @@ mod tests { #[cfg_attr(feature = "structural_renderer", derive(serde::Serialize))] struct GammaData; - impl Grouped<MockGroup> for GammaData { + /// # Safety + /// + /// This implementation is only for testing purposes to satisfy trait bounds. + /// Since this code only constructs `AnyOutput` and calls methods like + /// `downcast`, `is`, `restore`, `route_chain`, and `route_renderer` — + /// none of which involve `ProgramCollect::do_chain` or + /// `ProgramCollect::render` — the type/member_id correspondence is + /// never exploited in an unsafe way here. + /// The caller must ensure that the associated `member_id` correctly + /// corresponds to the type's role in the group. + unsafe impl Grouped<MockGroup> for GammaData { fn member_id() -> MockGroup { MockGroup::Gamma } @@ -369,7 +445,17 @@ mod tests { x: i32, } - impl Grouped<MockGroup> for SerData { + /// SAFETY: + /// + /// This implementation is only for testing purposes to satisfy trait bounds. + /// Since this code only constructs `AnyOutput` and calls methods like + /// `downcast`, `is`, `restore`, `route_chain`, and `route_renderer` — + /// none of which involve `ProgramCollect::do_chain` or + /// `ProgramCollect::render` — the type/member_id correspondence is + /// never exploited in an unsafe way here. + /// The caller must ensure that the associated `member_id` correctly + /// corresponds to the type's role in the group. + unsafe impl Grouped<MockGroup> for SerData { fn member_id() -> MockGroup { MockGroup::Gamma } @@ -396,13 +482,33 @@ mod tests { b: String, } - impl Grouped<MockGroup> for SerA { + /// SAFETY: + /// + /// This implementation is only for testing purposes to satisfy trait bounds. + /// Since this code only constructs `AnyOutput` and calls methods like + /// `downcast`, `is`, `restore`, `route_chain`, and `route_renderer` — + /// none of which involve `ProgramCollect::do_chain` or + /// `ProgramCollect::render` — the type/member_id correspondence is + /// never exploited in an unsafe way here. + /// The caller must ensure that the associated `member_id` correctly + /// corresponds to the type's role in the group. + unsafe impl Grouped<MockGroup> for SerA { fn member_id() -> MockGroup { MockGroup::Alpha } } - impl Grouped<MockGroup> for SerB { + /// SAFETY: + /// + /// This implementation is only for testing purposes to satisfy trait bounds. + /// Since this code only constructs `AnyOutput` and calls methods like + /// `downcast`, `is`, `restore`, `route_chain`, and `route_renderer` — + /// none of which involve `ProgramCollect::do_chain` or + /// `ProgramCollect::render` — the type/member_id correspondence is + /// never exploited in an unsafe way here. + /// The caller must ensure that the associated `member_id` correctly + /// corresponds to the type's role in the group. + unsafe impl Grouped<MockGroup> for SerB { fn member_id() -> MockGroup { MockGroup::Beta } diff --git a/mingling_core/src/any/group.rs b/mingling_core/src/any/group.rs index 2813ad5..5e5e347 100644 --- a/mingling_core/src/any/group.rs +++ b/mingling_core/src/any/group.rs @@ -2,10 +2,14 @@ use crate::{AnyOutput, ChainProcess, ProgramCollect, Routable}; /// Used to mark a type with a unique enum ID, assisting dynamic dispatch /// -/// **Note:** Unlike earlier versions, `Grouped` no longer requires `Serialize` -/// even when the `structural_renderer` feature is enabled. Structured output is -/// controlled separately via the \[`StructuralData`\] trait. -pub trait Grouped<Group> +/// # Safety +/// +/// The returned `Group` value is an enum variant created by `register_type!` when +/// registering the type's ID. Whether the variant matches correctly is guaranteed +/// by `Grouped derive` or macros like `pack!`. If implemented manually, and the +/// type name written in `member_id()` does not match the actually registered type, +/// dispatching to that type will result in **100% undefined behavior**. +pub unsafe trait Grouped<Group> where Self: Sized + 'static, { diff --git a/mingling_core/src/asset.rs b/mingling_core/src/asset.rs index 9b9a5d4..f26952b 100644 --- a/mingling_core/src/asset.rs +++ b/mingling_core/src/asset.rs @@ -1,26 +1,9 @@ -#[doc(hidden)] -pub mod chain; - -#[doc(hidden)] -pub mod dispatcher; - -#[doc(hidden)] -pub mod enum_tag; - -#[doc(hidden)] -pub mod global_resource; - -#[doc(hidden)] -pub mod help; - -#[doc(hidden)] -pub mod lazy_resource; - -#[doc(hidden)] -pub mod node; - -#[doc(hidden)] -pub mod renderer; - -#[doc(hidden)] -pub mod routable; +pub(crate) mod chain; +pub(crate) mod dispatcher; +pub(crate) mod enum_tag; +pub(crate) mod global_resource; +pub(crate) mod help; +pub(crate) mod lazy_resource; +pub(crate) mod node; +pub(crate) mod renderer; +pub(crate) mod routable; diff --git a/mingling_core/src/asset/global_resource.rs b/mingling_core/src/asset/global_resource.rs index a610378..19374e7 100644 --- a/mingling_core/src/asset/global_resource.rs +++ b/mingling_core/src/asset/global_resource.rs @@ -184,7 +184,10 @@ pub trait ResourceMarker { C: ProgramCollect<Enum = C> + 'static; } -impl<T: Default + Clone + Send + Sync + 'static> ResourceMarker for T { +impl<T> ResourceMarker for T +where + T: Default + Clone + Send + Sync + 'static, +{ fn res_clone(&self) -> Self { Clone::clone(self) } diff --git a/mingling_core/src/build.rs b/mingling_core/src/build.rs new file mode 100644 index 0000000..7918f3a --- /dev/null +++ b/mingling_core/src/build.rs @@ -0,0 +1,13 @@ +#[doc(hidden)] +#[cfg(feature = "comp")] +mod comp; + +#[cfg(feature = "comp")] +pub use comp::*; + +#[doc(hidden)] +#[cfg(feature = "pathf")] +mod pathf; + +#[cfg(feature = "pathf")] +pub use pathf::*; diff --git a/mingling_core/src/builds/comp.rs b/mingling_core/src/build/comp.rs index 2abb1e1..2abb1e1 100644 --- a/mingling_core/src/builds/comp.rs +++ b/mingling_core/src/build/comp.rs diff --git a/mingling_core/src/builds/pathf.rs b/mingling_core/src/build/pathf.rs index d8d4698..d8d4698 100644 --- a/mingling_core/src/builds/pathf.rs +++ b/mingling_core/src/build/pathf.rs diff --git a/mingling_core/src/builds.rs b/mingling_core/src/builds.rs deleted file mode 100644 index 3c52907..0000000 --- a/mingling_core/src/builds.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[doc(hidden)] -#[cfg(feature = "comp")] -pub mod comp; - -#[doc(hidden)] -#[cfg(feature = "pathf")] -pub mod pathf; diff --git a/mingling_core/src/lib.rs b/mingling_core/src/lib.rs index 31476c9..b9dbd06 100644 --- a/mingling_core/src/lib.rs +++ b/mingling_core/src/lib.rs @@ -1,3 +1,4 @@ +// #![deny(missing_docs)] //! Mingling Core //! //! # Intro @@ -8,7 +9,7 @@ //! //! Recommended to import [mingling](https://crates.io/crates/mingling) to use its features. -#![deny(missing_docs)] +// Private Modules mod any; mod asset; @@ -16,20 +17,65 @@ mod program; mod renderer; mod tester; +/// Module for setting up a `Mingling` program. +/// +/// This module provides the [`ProgramSetup`] type, which allows users to configure +/// and initialize the program's execution environment. +pub mod setup { + pub use crate::program::setup::ProgramSetup; +} + +/// This module provides result types for Mingling components. +/// +/// These are re-exported at the top level via `mingling::res`. +#[doc(hidden)] +pub mod core_res { + #[cfg(feature = "repl")] + pub use crate::program::repl_exec::res::*; +} + +/// Provides the runtime logic for Mingling's dynamic completion system. +/// +/// This module contains the core functionality for the "comp" (completion) feature, +/// which enables dynamic tab-completion and input suggestion capabilities within +/// Mingling applications. +#[cfg(feature = "comp")] +pub(crate) mod comp; + +/// Provides Mingling's build script module, used in `build.rs` to provide build-time behavior for certain features. +/// +/// To use it, add the following to your `Cargo.toml` under `[build-dependencies]`, and enable the features +/// that require build-time behavior from the crate: +/// +/// ```toml +/// [build-dependencies.mingling] +/// version = "0.3.0" +/// features = [ +/// "build", // Enable it +/// "comp", // If you need completion-related build-time behavior, enable this as well +/// ] +/// ``` +#[cfg(feature = "build")] +#[doc(hidden)] +pub mod build; + +// Public Modules + /// Provides a toolkit for `Mingling` testing capabilities. pub mod test { pub use crate::tester::*; } -#[cfg(feature = "structural_renderer")] -pub use crate::renderer::structural::StructuralRenderer; +/// Provided for framework developers +pub mod debug; // 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::structural::StructuralData` (through the inner alias). -pub use crate::any::group::*; -pub use crate::any::*; +#[cfg(feature = "structural_renderer")] +pub use crate::renderer::structural::StructuralRenderer; +pub use crate::any::*; pub use crate::asset::chain::*; pub use crate::asset::dispatcher::*; pub use crate::asset::enum_tag::*; @@ -39,74 +85,32 @@ pub use crate::asset::lazy_resource::*; pub use crate::asset::node::*; pub use crate::asset::renderer::*; pub use crate::asset::routable::*; +#[cfg(feature = "comp")] +pub use crate::comp::*; +pub use crate::program::*; +pub use crate::renderer::render_result::*; /// All error types of `Mingling` pub mod error { pub use crate::asset::chain::error::*; pub use crate::exec::error::*; pub use crate::program::error::*; + #[cfg(feature = "structural_renderer")] pub use crate::renderer::structural::error::*; - #[cfg(feature = "pathf")] - pub use mingling_pathf::error::*; -} - -pub use crate::program::*; - -pub use crate::renderer::render_result::*; - -#[cfg(feature = "builds")] -#[doc(hidden)] -pub mod builds; - -/// Provides build scripts for users -#[cfg(feature = "builds")] -pub mod build { - #[cfg(feature = "comp")] - pub use crate::builds::comp::*; #[cfg(feature = "pathf")] - pub use crate::builds::pathf::*; + pub use mingling_pathf::error::*; } -/// Provided for framework developers -pub mod debug; - -#[cfg(feature = "comp")] #[doc(hidden)] -pub mod comp; - -#[cfg(feature = "comp")] -pub use crate::comp::*; +mod private; -/// Module for setting up a `Mingling` program. +/// Internal API provided by Mingling Core /// -/// This module provides the [`ProgramSetup`] type, which allows users to configure -/// and initialize the program's execution environment. -pub mod setup { - pub use crate::program::setup::ProgramSetup; -} - -/// Private API — not intended for direct use. +/// These are used by macros and are not exposed to users, but are still accessible externally. #[doc(hidden)] +#[allow(unused_imports)] pub mod __private { - use crate::ProgramCollect; - - /// Sealed trait for `StructuralData` — only implementable via derive macro. - pub trait StructuralDataSealed<C> - where - C: ProgramCollect<Enum = C>, - { - } - - /// Re-export so the derive macro can reference the trait without - /// conflicting with the derive macro name at `::mingling::StructuralData`. - #[cfg(feature = "structural_renderer")] - pub use crate::renderer::structural::structural_data::StructuralData; -} - -#[doc(hidden)] -pub mod core_res { - #[cfg(feature = "repl")] - pub use crate::program::repl_exec::res::ResREPL; + pub use crate::private::*; } diff --git a/mingling_core/src/private.rs b/mingling_core/src/private.rs new file mode 100644 index 0000000..371ada2 --- /dev/null +++ b/mingling_core/src/private.rs @@ -0,0 +1,12 @@ +/// Sealed trait for `StructuralData` — only implementable via derive macro. +#[cfg(feature = "structural_renderer")] +pub trait StructuralDataSealed<C> +where + C: crate::ProgramCollect<Enum = C>, +{ +} + +/// Re-export so the derive macro can reference the trait without +/// conflicting with the derive macro name at `::mingling::StructuralData`. +#[cfg(feature = "structural_renderer")] +pub use crate::renderer::structural::structural_data::StructuralData; diff --git a/mingling_core/src/program/collection/mock.rs b/mingling_core/src/program/collection/mock.rs index 5847f10..dbe4789 100644 --- a/mingling_core/src/program/collection/mock.rs +++ b/mingling_core/src/program/collection/mock.rs @@ -23,9 +23,12 @@ pub enum MockProgramCollect { Bar, } -impl Grouped<MockProgramCollect> for MockProgramCollect { +/// SAFETY: This is a mock type used only for temporary testing. +/// It will never actually enter the macro system. +/// The internal `panic!` ensures that `member_id` will never be executed. +unsafe impl Grouped<MockProgramCollect> for MockProgramCollect { fn member_id() -> MockProgramCollect { - MockProgramCollect::Foo + panic!("Attempting to read an unsafe enum type"); } } diff --git a/mingling_core/src/program/hook.rs b/mingling_core/src/program/hook.rs index 48f632f..7d94a21 100644 --- a/mingling_core/src/program/hook.rs +++ b/mingling_core/src/program/hook.rs @@ -695,7 +695,17 @@ mod tests { } } - impl Grouped<MockHookEnum> for MockHookEnum { + /// SAFETY: + /// + /// This implementation is only for testing purposes to satisfy trait bounds. + /// Since this code only constructs `AnyOutput` and calls methods like + /// `downcast`, `is`, `restore`, `route_chain`, and `route_renderer` — + /// none of which involve `ProgramCollect::do_chain` or + /// `ProgramCollect::render` — the type/member_id correspondence is + /// never exploited in an unsafe way here. + /// The caller must ensure that the associated `member_id` correctly + /// corresponds to the type's role in the group. + unsafe impl Grouped<MockHookEnum> for MockHookEnum { fn member_id() -> MockHookEnum { MockHookEnum::A } diff --git a/mingling_core/src/renderer/render_result.rs b/mingling_core/src/renderer/render_result.rs index c38522a..8757376 100644 --- a/mingling_core/src/renderer/render_result.rs +++ b/mingling_core/src/renderer/render_result.rs @@ -6,7 +6,7 @@ use std::{ use crate::RenderResultMode::{Stderr, Stdout}; /// Render result, containing the rendered text content. -#[derive(Default, Debug, PartialEq)] +#[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct RenderResult { /// Whether the output should be written immediately. /// |
