alma 0.1.1

A Bevy-native modal text editor with Vim-style navigation.
Documentation
use crate::plugin::{
    PluginWorkspaceIoCompletion, PluginWorkspaceObserveOutcome, PluginWorkspaceObserveOutcomeShape,
    PluginWorkspaceReadError, PluginWorkspaceReadSuccess, PluginWorkspaceWriteError,
    PluginWorkspaceWriteSuccess, WorkspaceAccessKind,
};
use std::fmt::{Display, Formatter};

/// Redacted workspace I/O completion shape.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum PluginRuntimeTraceWorkspaceIoCompletion {
    /// Completed read request.
    Read {
        /// Normalized workspace path byte length.
        path_byte_len: usize,
        /// Read outcome.
        outcome: PluginRuntimeTraceWorkspaceReadOutcome,
    },
    /// Completed write request.
    Write {
        /// Normalized workspace path byte length.
        path_byte_len: usize,
        /// Write outcome.
        outcome: PluginRuntimeTraceWorkspaceWriteOutcome,
    },
}

impl PluginRuntimeTraceWorkspaceIoCompletion {
    /// Returns the completed operation kind.
    #[must_use]
    pub const fn kind(&self) -> WorkspaceAccessKind {
        match self {
            Self::Read { .. } => WorkspaceAccessKind::Read,
            Self::Write { .. } => WorkspaceAccessKind::Write,
        }
    }

    /// Returns the workspace path byte length.
    #[must_use]
    pub const fn path_byte_len(&self) -> usize {
        match self {
            Self::Read { path_byte_len, .. } | Self::Write { path_byte_len, .. } => *path_byte_len,
        }
    }

    /// Returns whether the operation succeeded.
    #[must_use]
    pub const fn is_ok(&self) -> bool {
        match self {
            Self::Read { outcome, .. } => outcome.is_ok(),
            Self::Write { outcome, .. } => outcome.is_ok(),
        }
    }
}

impl From<&PluginWorkspaceIoCompletion> for PluginRuntimeTraceWorkspaceIoCompletion {
    fn from(completion: &PluginWorkspaceIoCompletion) -> Self {
        match completion {
            PluginWorkspaceIoCompletion::Read(completion) => Self::Read {
                path_byte_len: completion.workspace_relative_path().len(),
                outcome: PluginRuntimeTraceWorkspaceReadOutcome::from(completion.outcome()),
            },
            PluginWorkspaceIoCompletion::Write(completion) => Self::Write {
                path_byte_len: completion.workspace_relative_path().len(),
                outcome: PluginRuntimeTraceWorkspaceWriteOutcome::from(completion.outcome()),
            },
        }
    }
}

impl Display for PluginRuntimeTraceWorkspaceIoCompletion {
    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Read {
                path_byte_len,
                outcome,
            } => write!(
                formatter,
                "read path_byte_len={path_byte_len} outcome={outcome}"
            ),
            Self::Write {
                path_byte_len,
                outcome,
            } => write!(
                formatter,
                "write path_byte_len={path_byte_len} outcome={outcome}"
            ),
        }
    }
}

/// Redacted workspace read outcome.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum PluginRuntimeTraceWorkspaceReadOutcome {
    /// Read succeeded.
    Ok {
        /// Escaped display path byte length.
        display_path_byte_len: usize,
        /// Bounded file byte length.
        byte_len: usize,
    },
    /// Filesystem policy or I/O rejected the read.
    Rejected,
}

impl PluginRuntimeTraceWorkspaceReadOutcome {
    /// Returns whether the read succeeded.
    #[must_use]
    pub const fn is_ok(self) -> bool {
        matches!(self, Self::Ok { .. })
    }
}

impl From<&Result<PluginWorkspaceReadSuccess, PluginWorkspaceReadError>>
    for PluginRuntimeTraceWorkspaceReadOutcome
{
    fn from(outcome: &Result<PluginWorkspaceReadSuccess, PluginWorkspaceReadError>) -> Self {
        match outcome {
            Ok(success) => Self::Ok {
                display_path_byte_len: success.display_path().as_str().len(),
                byte_len: success.bytes().len(),
            },
            Err(PluginWorkspaceReadError::Read(_source)) => Self::Rejected,
        }
    }
}

impl Display for PluginRuntimeTraceWorkspaceReadOutcome {
    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Ok {
                display_path_byte_len,
                byte_len,
            } => write!(
                formatter,
                "ok display_path_byte_len={display_path_byte_len} byte_len={byte_len}"
            ),
            Self::Rejected => formatter.write_str("rejected"),
        }
    }
}

/// Redacted workspace observation task outcome.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum PluginRuntimeTraceWorkspaceObserveTaskOutcome {
    /// Observation returned bounded bytes.
    Bytes {
        /// Bounded file byte length.
        byte_len: usize,
    },
    /// Filesystem policy or I/O rejected the observation.
    Rejected,
}

impl PluginRuntimeTraceWorkspaceObserveTaskOutcome {
    /// Returns whether the observation produced bytes.
    #[must_use]
    pub const fn is_ok(self) -> bool {
        matches!(self, Self::Bytes { .. })
    }
}

impl From<&PluginWorkspaceObserveOutcome> for PluginRuntimeTraceWorkspaceObserveTaskOutcome {
    fn from(outcome: &PluginWorkspaceObserveOutcome) -> Self {
        Self::from(outcome.shape())
    }
}

impl From<PluginWorkspaceObserveOutcomeShape> for PluginRuntimeTraceWorkspaceObserveTaskOutcome {
    fn from(outcome: PluginWorkspaceObserveOutcomeShape) -> Self {
        match outcome {
            PluginWorkspaceObserveOutcomeShape::Bytes { byte_len } => Self::Bytes { byte_len },
            PluginWorkspaceObserveOutcomeShape::Rejected => Self::Rejected,
        }
    }
}

impl Display for PluginRuntimeTraceWorkspaceObserveTaskOutcome {
    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Bytes { byte_len } => write!(formatter, "bytes byte_len={byte_len}"),
            Self::Rejected => formatter.write_str("rejected"),
        }
    }
}

/// Redacted workspace write outcome.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum PluginRuntimeTraceWorkspaceWriteOutcome {
    /// Write succeeded.
    Ok {
        /// Escaped display path byte length.
        display_path_byte_len: usize,
    },
    /// Payload exceeded the accepted byte budget before filesystem policy ran.
    PayloadTooLarge {
        /// Observed payload bytes.
        size: u64,
        /// Accepted payload bytes.
        max_size: u64,
    },
    /// Filesystem policy or I/O rejected the write.
    Rejected,
}

impl PluginRuntimeTraceWorkspaceWriteOutcome {
    /// Returns whether the write succeeded.
    #[must_use]
    pub const fn is_ok(self) -> bool {
        matches!(self, Self::Ok { .. })
    }
}

impl From<&Result<PluginWorkspaceWriteSuccess, PluginWorkspaceWriteError>>
    for PluginRuntimeTraceWorkspaceWriteOutcome
{
    fn from(outcome: &Result<PluginWorkspaceWriteSuccess, PluginWorkspaceWriteError>) -> Self {
        match outcome {
            Ok(success) => Self::Ok {
                display_path_byte_len: success.display_path().as_str().len(),
            },
            Err(PluginWorkspaceWriteError::PayloadTooLarge { size, max_size }) => {
                Self::PayloadTooLarge {
                    size: *size,
                    max_size: *max_size,
                }
            }
            Err(PluginWorkspaceWriteError::Write(_source)) => Self::Rejected,
        }
    }
}

impl Display for PluginRuntimeTraceWorkspaceWriteOutcome {
    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Ok {
                display_path_byte_len,
            } => write!(
                formatter,
                "ok display_path_byte_len={display_path_byte_len}"
            ),
            Self::PayloadTooLarge { size, max_size } => {
                write!(
                    formatter,
                    "payload-too-large size={size} max_size={max_size}"
                )
            }
            Self::Rejected => formatter.write_str("rejected"),
        }
    }
}