alma 0.1.1

A Bevy-native modal text editor with Vim-style navigation.
Documentation
//! Successful-return and discard proof batches.

use super::super::{
    PluginEffectDiscardReport, PluginWorkspaceIoDiscardReport,
    PluginWorkspaceObserveTaskDiscardReport, SealedPluginEffectBatch, SealedPluginWorkspaceIoBatch,
    SealedPluginWorkspaceObserveTaskBatch,
};
use crate::plugin::PluginIdentity;
use std::fmt::{Debug, Formatter};

/// Sealed work from one successful guest update.
pub struct PluginHostImportBatches {
    /// Editor effects.
    effects: SealedPluginEffectBatch,
    /// Workspace I/O.
    workspace_io: SealedPluginWorkspaceIoBatch,
    /// Workspace observation tasks.
    workspace_observe_tasks: SealedPluginWorkspaceObserveTaskBatch,
}

/// Successful-return work split by the next owner boundary.
pub struct PluginHostImportOwnerAndTaskBatches {
    /// Successful-return work for non-runtime owners.
    pub owner_batches: PluginHostOwnerBatches,
    /// Runtime-owned workspace observation tasks.
    pub workspace_observe_tasks: SealedPluginWorkspaceObserveTaskBatch,
}

/// Successful-return work split by sealed batch kind.
pub struct PluginHostImportBatchesParts {
    /// Editor effects sealed for ECS owners.
    pub effects: SealedPluginEffectBatch,
    /// Workspace I/O sealed for filesystem-policy execution.
    pub workspace_io: SealedPluginWorkspaceIoBatch,
    /// Workspace observation tasks sealed for runtime scheduling.
    pub workspace_observe_tasks: SealedPluginWorkspaceObserveTaskBatch,
}

impl PluginHostImportBatches {
    /// Builds one successful-return proof from sealed work with one plugin identity.
    pub(super) fn new(
        effects: SealedPluginEffectBatch,
        workspace_io: SealedPluginWorkspaceIoBatch,
        workspace_observe_tasks: SealedPluginWorkspaceObserveTaskBatch,
    ) -> Self {
        assert_eq!(
            effects.identity_proof(),
            workspace_io.identity_proof(),
            "plugin host import batches must share one identity",
        );
        assert_eq!(
            effects.identity_proof(),
            workspace_observe_tasks.identity_proof(),
            "plugin host import batches must share one identity",
        );
        Self {
            effects,
            workspace_io,
            workspace_observe_tasks,
        }
    }

    /// Splits successful-return work into owner-published work and runtime-owned task work.
    #[must_use]
    pub(crate) fn into_owner_and_workspace_observe_tasks(
        self,
    ) -> PluginHostImportOwnerAndTaskBatches {
        let Self {
            effects,
            workspace_io,
            workspace_observe_tasks,
        } = self;
        PluginHostImportOwnerAndTaskBatches {
            owner_batches: PluginHostOwnerBatches::from_parts(effects, workspace_io),
            workspace_observe_tasks,
        }
    }

    /// Splits successful-return work by sealed batch kind.
    #[must_use]
    pub fn into_parts(self) -> PluginHostImportBatchesParts {
        PluginHostImportBatchesParts {
            effects: self.effects,
            workspace_io: self.workspace_io,
            workspace_observe_tasks: self.workspace_observe_tasks,
        }
    }
}

/// Successful-return work that must be published by non-runtime owners.
#[derive(Eq, PartialEq)]
pub struct PluginHostOwnerBatches {
    /// Editor effects sealed for ECS owners.
    effects: SealedPluginEffectBatch,
    /// Workspace I/O sealed for filesystem-policy execution.
    workspace_io: SealedPluginWorkspaceIoBatch,
}

impl PluginHostOwnerBatches {
    /// Rebuilds paired owner work after an owner admission proof is abandoned.
    pub(crate) fn from_parts(
        effects: SealedPluginEffectBatch,
        workspace_io: SealedPluginWorkspaceIoBatch,
    ) -> Self {
        assert_eq!(
            effects.identity_proof(),
            workspace_io.identity_proof(),
            "plugin owner batches must share one identity",
        );
        Self {
            effects,
            workspace_io,
        }
    }

    /// Returns the plugin identity for display and serialization.
    #[must_use]
    pub fn identity(&self) -> &str {
        self.identity_proof().as_str()
    }

    /// Returns the identity proof shared by owner-published work.
    #[must_use]
    pub const fn identity_proof(&self) -> &PluginIdentity {
        self.effects.identity_proof()
    }

    /// Returns the unpublished editor effects.
    #[must_use]
    pub const fn effects(&self) -> &SealedPluginEffectBatch {
        &self.effects
    }

    /// Returns the unpublished workspace I/O.
    #[must_use]
    pub const fn workspace_io(&self) -> &SealedPluginWorkspaceIoBatch {
        &self.workspace_io
    }

    /// Returns whether the paired owner work is an empty scheduler no-op.
    #[must_use]
    pub const fn is_empty(&self) -> bool {
        self.effects.is_empty() && self.workspace_io.is_empty()
    }

    /// Discards paired owner work that will not be retried.
    #[must_use]
    pub fn discard(self) -> PluginHostOwnerDiscardReport {
        let parts = self.into_parts();
        PluginHostOwnerDiscardReport::new(parts.effects.discard(), parts.workspace_io.discard())
    }

    /// Splits owner-published work by owning queue.
    #[must_use]
    pub fn into_parts(self) -> PluginHostOwnerBatchesParts {
        PluginHostOwnerBatchesParts {
            effects: self.effects,
            workspace_io: self.workspace_io,
        }
    }

    /// Builds owner batches for focused runtime scheduling tests.
    #[cfg(test)]
    pub(in crate::plugin) fn for_test(
        effects: SealedPluginEffectBatch,
        workspace_io: SealedPluginWorkspaceIoBatch,
    ) -> Self {
        assert_eq!(effects.identity_proof(), workspace_io.identity_proof());
        Self::from_parts(effects, workspace_io)
    }
}

/// Paired owner work split by owning queue.
pub struct PluginHostOwnerBatchesParts {
    /// Editor effects sealed for ECS owners.
    pub effects: SealedPluginEffectBatch,
    /// Workspace I/O sealed for filesystem-policy execution.
    pub workspace_io: SealedPluginWorkspaceIoBatch,
}

/// Redacted discard report for paired owner work.
#[derive(Eq, PartialEq)]
pub struct PluginHostOwnerDiscardReport {
    /// Discarded editor effects.
    effects: PluginEffectDiscardReport,
    /// Discarded workspace I/O.
    workspace_io: PluginWorkspaceIoDiscardReport,
}

impl PluginHostOwnerDiscardReport {
    /// Builds a paired owner discard report.
    pub(super) fn new(
        effects: PluginEffectDiscardReport,
        workspace_io: PluginWorkspaceIoDiscardReport,
    ) -> Self {
        assert_eq!(
            effects.identity_proof(),
            workspace_io.identity_proof(),
            "plugin owner discard report must share one identity",
        );
        Self {
            effects,
            workspace_io,
        }
    }

    /// Returns the discarded plugin identity for display and serialization.
    #[must_use]
    pub fn identity(&self) -> &str {
        self.identity_proof().as_str()
    }

    /// Returns the validated identity shared by the discarded owner work.
    #[must_use]
    pub const fn identity_proof(&self) -> &PluginIdentity {
        self.effects.identity_proof()
    }

    /// Returns discarded editor effects.
    #[must_use]
    pub const fn effects(&self) -> &PluginEffectDiscardReport {
        &self.effects
    }

    /// Returns discarded workspace I/O.
    #[must_use]
    pub const fn workspace_io(&self) -> &PluginWorkspaceIoDiscardReport {
        &self.workspace_io
    }
}

impl Debug for PluginHostOwnerDiscardReport {
    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
        formatter
            .debug_struct("PluginHostOwnerDiscardReport")
            .field("identity", self.identity_proof())
            .field("discarded_effect_count", &self.effects.discarded_effects())
            .field(
                "discarded_workspace_io_request_count",
                &self.workspace_io.discarded_requests(),
            )
            .finish()
    }
}

impl Debug for PluginHostOwnerBatches {
    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
        formatter
            .debug_struct("PluginHostOwnerBatches")
            .field("identity", self.identity_proof())
            .field("effect_count", &self.effects.effect_count())
            .field(
                "workspace_io_request_count",
                &self.workspace_io.request_count(),
            )
            .finish()
    }
}

impl Debug for PluginHostImportBatches {
    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
        formatter
            .debug_struct("PluginHostImportBatches")
            .field("identity", self.effects.identity_proof())
            .field("effect_count", &self.effects.effect_count())
            .field(
                "workspace_io_request_count",
                &self.workspace_io.request_count(),
            )
            .field(
                "workspace_observe_task_count",
                &self.workspace_observe_tasks.task_count(),
            )
            .finish()
    }
}

/// Discard report for one failed guest update.
#[derive(Eq, PartialEq)]
pub struct PluginHostImportDiscardReport {
    /// Editor effect discard report.
    effects: PluginEffectDiscardReport,
    /// Workspace I/O discard report.
    workspace_io: PluginWorkspaceIoDiscardReport,
    /// Workspace observation task discard report.
    workspace_observe_tasks: PluginWorkspaceObserveTaskDiscardReport,
}

impl PluginHostImportDiscardReport {
    /// Builds a failed-update discard report.
    pub(super) fn new(
        effects: PluginEffectDiscardReport,
        workspace_io: PluginWorkspaceIoDiscardReport,
        workspace_observe_tasks: PluginWorkspaceObserveTaskDiscardReport,
    ) -> Self {
        assert_eq!(
            effects.identity_proof(),
            workspace_io.identity_proof(),
            "plugin host import discard report must share one identity",
        );
        assert_eq!(
            effects.identity_proof(),
            workspace_observe_tasks.identity_proof(),
            "plugin host import discard report must share one identity",
        );
        Self {
            effects,
            workspace_io,
            workspace_observe_tasks,
        }
    }

    /// Returns the plugin identity whose update work was discarded.
    #[must_use]
    pub fn identity(&self) -> &str {
        self.identity_proof().as_str()
    }

    /// Returns the validated identity shared by all discarded work.
    #[must_use]
    pub const fn identity_proof(&self) -> &PluginIdentity {
        self.effects.identity_proof()
    }

    /// Returns discarded editor effects.
    #[must_use]
    pub const fn effects(&self) -> &PluginEffectDiscardReport {
        &self.effects
    }

    /// Returns discarded workspace I/O.
    #[must_use]
    pub const fn workspace_io(&self) -> &PluginWorkspaceIoDiscardReport {
        &self.workspace_io
    }

    /// Returns discarded workspace observation tasks.
    #[must_use]
    pub const fn workspace_observe_tasks(&self) -> &PluginWorkspaceObserveTaskDiscardReport {
        &self.workspace_observe_tasks
    }
}

impl Debug for PluginHostImportDiscardReport {
    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
        formatter
            .debug_struct("PluginHostImportDiscardReport")
            .field("identity", self.identity_proof())
            .field("discarded_effect_count", &self.effects.discarded_effects())
            .field(
                "discarded_workspace_io_request_count",
                &self.workspace_io.discarded_requests(),
            )
            .field(
                "discarded_workspace_observe_task_count",
                &self.workspace_observe_tasks.discarded_tasks(),
            )
            .finish()
    }
}