use std::{collections::HashMap, sync::Mutex};
use reovim_kernel::api::v1::{Service, ServiceRegistry};
use crate::{ClientId, ExtensionMap};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExtensionScope {
Shared,
Client,
}
pub struct BridgeContext<'a> {
pub client_id: ClientId,
pub shared_extensions: &'a ExtensionMap,
opponents: &'a [(ClientId, &'a ExtensionMap)],
}
impl<'a> BridgeContext<'a> {
#[must_use]
pub const fn new(
client_id: ClientId,
shared_extensions: &'a ExtensionMap,
opponents: &'a [(ClientId, &'a ExtensionMap)],
) -> Self {
Self {
client_id,
shared_extensions,
opponents,
}
}
pub fn for_each_opponent(&self, mut f: impl FnMut(ClientId, &ExtensionMap)) {
for &(id, ext) in self.opponents {
f(id, ext);
}
}
#[must_use]
pub const fn opponent_count(&self) -> usize {
self.opponents.len()
}
}
pub trait ExtensionStateBridge: Send + Sync + 'static {
fn kind(&self) -> &'static str;
fn scope(&self) -> ExtensionScope;
fn snapshot(&self, extensions: &ExtensionMap) -> Option<serde_json::Value>;
fn is_active(&self, extensions: &ExtensionMap) -> bool;
fn on_mode_changed(&self, _from: &str, _to: &str, _extensions: &mut ExtensionMap) {}
#[cfg_attr(coverage_nightly, coverage(off))]
fn on_cursor_moved(&self, _line: usize, _col: usize, _extensions: &mut ExtensionMap) {}
fn snapshot_with_context(
&self,
extensions: &ExtensionMap,
_context: &BridgeContext<'_>,
) -> Option<serde_json::Value> {
self.snapshot(extensions)
}
fn tick(
&self,
_client_extensions: &mut ExtensionMap,
_shared_extensions: &mut ExtensionMap,
_services: &ServiceRegistry,
) -> bool {
false
}
}
pub struct BridgeRegistry {
bridges: HashMap<&'static str, Box<dyn ExtensionStateBridge>>,
available_kinds: Vec<&'static str>,
}
impl BridgeRegistry {
#[must_use]
pub fn new() -> Self {
Self {
bridges: HashMap::new(),
available_kinds: Vec::new(),
}
}
pub fn register(&mut self, bridge: impl ExtensionStateBridge) {
self.bridges.insert(bridge.kind(), Box::new(bridge));
}
pub fn register_boxed(&mut self, bridge: Box<dyn ExtensionStateBridge>) {
self.bridges.insert(bridge.kind(), bridge);
}
#[must_use]
pub fn get(&self, kind: &str) -> Option<&dyn ExtensionStateBridge> {
self.bridges.get(kind).map(AsRef::as_ref)
}
#[must_use]
pub fn kinds(&self) -> Vec<&'static str> {
let mut kinds: Vec<_> = self.bridges.keys().copied().collect();
kinds.sort_unstable();
kinds
}
pub fn values(&self) -> impl Iterator<Item = &dyn ExtensionStateBridge> {
self.bridges.values().map(AsRef::as_ref)
}
pub fn set_available_kinds(&mut self, kinds: Vec<&'static str>) {
self.available_kinds = kinds;
}
#[must_use]
pub fn available_kinds(&self) -> &[&'static str] {
&self.available_kinds
}
}
impl Default for BridgeRegistry {
fn default() -> Self {
Self::new()
}
}
impl std::fmt::Debug for BridgeRegistry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BridgeRegistry")
.field("count", &self.bridges.len())
.field("kinds", &self.kinds())
.field("available_kinds", &self.available_kinds)
.finish()
}
}
pub struct BridgeProvider {
bridges: Mutex<Vec<Box<dyn ExtensionStateBridge>>>,
}
impl Default for BridgeProvider {
fn default() -> Self {
Self {
bridges: Mutex::new(Vec::new()),
}
}
}
impl Service for BridgeProvider {}
impl BridgeProvider {
pub fn register(&self, bridge: impl ExtensionStateBridge) {
self.bridges
.lock()
.expect("BridgeProvider lock poisoned")
.push(Box::new(bridge));
}
#[must_use]
pub fn take_bridges(&self) -> Vec<Box<dyn ExtensionStateBridge>> {
std::mem::take(&mut *self.bridges.lock().expect("BridgeProvider lock poisoned"))
}
}
impl std::fmt::Debug for BridgeProvider {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let count = self.bridges.lock().map_or(0, |b| b.len());
f.debug_struct("BridgeProvider")
.field("pending_bridges", &count)
.finish()
}
}
#[cfg(test)]
#[path = "tests/mod_tests.rs"]
mod tests;