nushell/crates/nu-plugin-test-support/src/fake_persistent_plugin.rs
Devyn Cairns 0c4d5330ee
Split the plugin crate (#12563)
# Description

This breaks `nu-plugin` up into four crates:

- `nu-plugin-protocol`: just the type definitions for the protocol, no
I/O. If someone wanted to wire up something more bare metal, maybe for
async I/O, they could use this.
- `nu-plugin-core`: the shared stuff between engine/plugin. Less stable
interface.
- `nu-plugin-engine`: everything required for the engine to talk to
plugins. Less stable interface.
- `nu-plugin`: everything required for the plugin to talk to the engine,
what plugin developers use. Should be the most stable interface.

No changes are made to the interface exposed by `nu-plugin` - it should
all still be there. Re-exports from `nu-plugin-protocol` or
`nu-plugin-core` are used as required. Plugins shouldn't ever have to
use those crates directly.

This should be somewhat faster to compile as `nu-plugin-engine` and
`nu-plugin` can compile in parallel, and the engine doesn't need
`nu-plugin` and plugins don't need `nu-plugin-engine` (except for test
support), so that should reduce what needs to be compiled too.

The only significant change here other than splitting stuff up was to
break the `source` out of `PluginCustomValue` and create a new
`PluginCustomValueWithSource` type that contains that instead. One bonus
of that is we get rid of the option and it's now more type-safe, but it
also means that the logic for that stuff (actually running the plugin
for custom value ops) can live entirely within the `nu-plugin-engine`
crate.

# User-Facing Changes
- New crates.
- Added `local-socket` feature for `nu` to try to make it possible to
compile without that support if needed.

# Tests + Formatting
- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- 🟢 `toolkit test`
- 🟢 `toolkit test stdlib`
2024-04-27 12:08:12 -05:00

76 lines
1.7 KiB
Rust

use std::{
any::Any,
sync::{Arc, OnceLock},
};
use nu_plugin_engine::{GetPlugin, PluginInterface};
use nu_protocol::{
engine::{EngineState, Stack},
PluginGcConfig, PluginIdentity, RegisteredPlugin, ShellError,
};
pub struct FakePersistentPlugin {
identity: PluginIdentity,
plugin: OnceLock<PluginInterface>,
}
impl FakePersistentPlugin {
pub fn new(identity: PluginIdentity) -> FakePersistentPlugin {
FakePersistentPlugin {
identity,
plugin: OnceLock::new(),
}
}
pub fn initialize(&self, interface: PluginInterface) {
self.plugin.set(interface).unwrap_or_else(|_| {
panic!("Tried to initialize an already initialized FakePersistentPlugin");
})
}
}
impl RegisteredPlugin for FakePersistentPlugin {
fn identity(&self) -> &PluginIdentity {
&self.identity
}
fn is_running(&self) -> bool {
true
}
fn pid(&self) -> Option<u32> {
None
}
fn set_gc_config(&self, _gc_config: &PluginGcConfig) {
// We don't have a GC
}
fn stop(&self) -> Result<(), ShellError> {
// We can't stop
Ok(())
}
fn reset(&self) -> Result<(), ShellError> {
// We can't stop
Ok(())
}
fn as_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
self
}
}
impl GetPlugin for FakePersistentPlugin {
fn get_plugin(
self: Arc<Self>,
_context: Option<(&EngineState, &mut Stack)>,
) -> Result<PluginInterface, ShellError> {
self.plugin
.get()
.cloned()
.ok_or_else(|| ShellError::PluginFailedToLoad {
msg: "FakePersistentPlugin was not initialized".into(),
})
}
}