use std::any::Any;
use std::marker::PhantomData;
use std::sync::Arc;
use crate::state::{EditorState, Transaction};
pub trait Plugin: Send + Sync + 'static {
const NAME: &'static str;
type State: Clone + Send + Sync + 'static;
fn init(&self, state: &EditorState) -> Self::State;
fn apply(
&self,
_tx: &Transaction,
_prev_state: &EditorState,
state: Self::State,
) -> Self::State {
state
}
}
pub struct PluginKey<P: Plugin>(PhantomData<fn() -> P>);
impl<P: Plugin> PluginKey<P> {
pub const fn new() -> Self {
PluginKey(PhantomData)
}
pub const fn name(&self) -> &'static str {
P::NAME
}
}
impl<P: Plugin> Default for PluginKey<P> {
fn default() -> Self {
Self::new()
}
}
impl<P: Plugin> Clone for PluginKey<P> {
fn clone(&self) -> Self {
*self
}
}
impl<P: Plugin> Copy for PluginKey<P> {}
pub(crate) trait StoredPlugin: Send + Sync {
fn name(&self) -> &'static str;
fn init_erased(&self, state: &EditorState) -> Box<dyn Any + Send + Sync>;
fn apply_erased(
&self,
tx: &Transaction,
prev_state: &EditorState,
state: &(dyn Any + Send + Sync),
) -> Box<dyn Any + Send + Sync>;
}
struct PluginAdapter<P: Plugin>(P);
impl<P: Plugin> StoredPlugin for PluginAdapter<P> {
fn name(&self) -> &'static str {
P::NAME
}
fn init_erased(&self, state: &EditorState) -> Box<dyn Any + Send + Sync> {
Box::new(self.0.init(state))
}
fn apply_erased(
&self,
tx: &Transaction,
prev_state: &EditorState,
state: &(dyn Any + Send + Sync),
) -> Box<dyn Any + Send + Sync> {
let typed: &P::State = state
.downcast_ref::<P::State>()
.expect("plugin state type mismatch — registry must be consistent");
Box::new(self.0.apply(tx, prev_state, typed.clone()))
}
}
#[derive(Clone, Default)]
pub struct PluginSet {
plugins: Vec<Arc<dyn StoredPlugin>>,
}
impl PluginSet {
pub fn new() -> Self {
Self::default()
}
pub fn with<P: Plugin>(mut self, plugin: P) -> Self {
self.plugins.push(Arc::new(PluginAdapter(plugin)));
self
}
pub fn len(&self) -> usize {
self.plugins.len()
}
pub fn is_empty(&self) -> bool {
self.plugins.is_empty()
}
pub(crate) fn iter(&self) -> impl Iterator<Item = &Arc<dyn StoredPlugin>> {
self.plugins.iter()
}
}
impl std::fmt::Debug for PluginSet {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PluginSet")
.field(
"plugins",
&self.plugins.iter().map(|p| p.name()).collect::<Vec<_>>(),
)
.finish()
}
}
#[derive(Clone, Default)]
pub(crate) struct PluginStates {
states: Vec<(&'static str, Arc<dyn Any + Send + Sync>)>,
set: PluginSet,
}
impl PluginStates {
pub(crate) fn from_set(set: PluginSet, state: &EditorState) -> Self {
let states = set
.iter()
.map(|p| (p.name(), Arc::from(p.init_erased(state))))
.collect();
PluginStates { states, set }
}
pub(crate) fn apply(&self, tx: &Transaction, prev_state: &EditorState) -> Self {
let new_states: Vec<(&'static str, Arc<dyn Any + Send + Sync>)> = self
.set
.iter()
.zip(self.states.iter())
.map(|(plugin, (name, state))| {
let next = plugin.apply_erased(tx, prev_state, state.as_ref());
(*name, Arc::from(next))
})
.collect();
PluginStates {
states: new_states,
set: self.set.clone(),
}
}
pub(crate) fn get<P: Plugin>(&self) -> Option<&P::State> {
self.states
.iter()
.find(|(n, _)| *n == P::NAME)
.and_then(|(_, s)| s.downcast_ref::<P::State>())
}
}
impl std::fmt::Debug for PluginStates {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PluginStates")
.field(
"plugins",
&self.states.iter().map(|(n, _)| *n).collect::<Vec<_>>(),
)
.finish()
}
}