alma 0.1.1

A Bevy-native modal text editor with Vim-style navigation.
Documentation
//! Static plugin config entries and effective grant projection.

use super::{PluginIdentity, PluginProposalPolicy};
use crate::plugin::{CURRENT_WIT_WORLD, PluginCapabilities, PluginManifest, PluginRuntimeLimits};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;

/// Static configuration for one Wasm plugin component.
#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct PluginConfig {
    /// Stable plugin identity used for grants and revocation.
    pub identity: String,
    /// Local component path.
    pub component_path: PathBuf,
    /// WIT world the component is expected to implement.
    pub wit_world: String,
    /// Whether this plugin may be loaded.
    pub enabled: bool,
    /// Maximum capability grants allowed by app config.
    pub capabilities: PluginCapabilities,
    /// Runtime execution limits for this plugin.
    pub runtime_limits: PluginRuntimeLimits,
    /// Proposal handling policy for this plugin.
    pub proposal_policy: PluginProposalPolicy,
}

impl PluginConfig {
    /// Returns whether this config can load a component for the current ABI.
    #[must_use]
    pub fn supports_current_world(&self) -> bool {
        self.wit_world == CURRENT_WIT_WORLD
    }

    /// Intersects this config's grants with a plugin manifest's requested capabilities.
    #[must_use]
    pub fn granted_manifest_capabilities(&self, manifest: &PluginManifest) -> PluginCapabilities {
        let Ok(config_identity) = PluginIdentity::try_new(self.identity.clone()) else {
            return PluginCapabilities::default();
        };
        let Ok(manifest_identity) = PluginIdentity::try_new(manifest.identity().to_owned()) else {
            return PluginCapabilities::default();
        };

        if !self.enabled
            || config_identity != manifest_identity
            || self.wit_world != manifest.wit_world()
            || self.wit_world != CURRENT_WIT_WORLD
        {
            return PluginCapabilities::default();
        }

        self.capabilities
            .intersection(manifest.requested_capabilities())
    }
}

impl Default for PluginConfig {
    fn default() -> Self {
        Self {
            identity: String::new(),
            component_path: PathBuf::new(),
            wit_world: String::from(CURRENT_WIT_WORLD),
            enabled: false,
            capabilities: PluginCapabilities::default(),
            runtime_limits: PluginRuntimeLimits::default(),
            proposal_policy: PluginProposalPolicy::default(),
        }
    }
}