mirror of
https://github.com/nushell/nushell.git
synced 2025-03-24 21:47:56 +01:00
# Description Because the plugin interface reader thread can be responsible for sending a drop notification, it's possible for it to end up in a deadlock where it's waiting for the response to the drop notification call. I decided that the best way to address this is to just discard the response and not wait for it. It's not really important to synchronize with the response to `Dropped`, so this is probably faster anyway. cc @ayax79, this is your issue where polars is getting stuck # User-Facing Changes - A bug fix - Custom value plugin: `custom-value handle update` command # Tests + Formatting Tried to add a test with a long pipeline with a lot of drops and run it over and over to reproduce the deadlock. - 🟢 `toolkit fmt` - 🟢 `toolkit clippy` - 🟢 `toolkit test` - 🟢 `toolkit test stdlib`
104 lines
2.7 KiB
Rust
104 lines
2.7 KiB
Rust
use std::{
|
|
collections::BTreeMap,
|
|
sync::{atomic::AtomicU64, Mutex},
|
|
};
|
|
|
|
use handle_custom_value::HandleCustomValue;
|
|
use nu_plugin::{serve_plugin, EngineInterface, MsgPackSerializer, Plugin, PluginCommand};
|
|
|
|
mod cool_custom_value;
|
|
mod handle_custom_value;
|
|
mod second_custom_value;
|
|
|
|
mod drop_check;
|
|
mod generate;
|
|
mod generate2;
|
|
mod handle_get;
|
|
mod handle_make;
|
|
mod handle_update;
|
|
mod update;
|
|
mod update_arg;
|
|
|
|
use drop_check::{DropCheck, DropCheckValue};
|
|
use generate::Generate;
|
|
use generate2::Generate2;
|
|
use handle_get::HandleGet;
|
|
use handle_make::HandleMake;
|
|
use handle_update::HandleUpdate;
|
|
use nu_protocol::{CustomValue, LabeledError, Spanned, Value};
|
|
use update::Update;
|
|
use update_arg::UpdateArg;
|
|
|
|
#[derive(Default)]
|
|
pub struct CustomValuePlugin {
|
|
counter: AtomicU64,
|
|
handles: Mutex<BTreeMap<u64, Value>>,
|
|
}
|
|
|
|
impl CustomValuePlugin {
|
|
pub fn new() -> Self {
|
|
Self::default()
|
|
}
|
|
}
|
|
|
|
impl Plugin for CustomValuePlugin {
|
|
fn commands(&self) -> Vec<Box<dyn PluginCommand<Plugin = Self>>> {
|
|
vec![
|
|
Box::new(Generate),
|
|
Box::new(Generate2),
|
|
Box::new(Update),
|
|
Box::new(UpdateArg),
|
|
Box::new(DropCheck),
|
|
Box::new(HandleGet),
|
|
Box::new(HandleMake),
|
|
Box::new(HandleUpdate),
|
|
]
|
|
}
|
|
|
|
fn custom_value_to_base_value(
|
|
&self,
|
|
_engine: &EngineInterface,
|
|
custom_value: Spanned<Box<dyn CustomValue>>,
|
|
) -> Result<Value, LabeledError> {
|
|
// HandleCustomValue depends on the plugin state to get.
|
|
if let Some(handle) = custom_value
|
|
.item
|
|
.as_any()
|
|
.downcast_ref::<HandleCustomValue>()
|
|
{
|
|
Ok(self
|
|
.handles
|
|
.lock()
|
|
.map_err(|err| LabeledError::new(err.to_string()))?
|
|
.get(&handle.0)
|
|
.cloned()
|
|
.unwrap_or_else(|| Value::nothing(custom_value.span)))
|
|
} else {
|
|
custom_value
|
|
.item
|
|
.to_base_value(custom_value.span)
|
|
.map_err(|err| err.into())
|
|
}
|
|
}
|
|
|
|
fn custom_value_dropped(
|
|
&self,
|
|
_engine: &EngineInterface,
|
|
custom_value: Box<dyn CustomValue>,
|
|
) -> Result<(), LabeledError> {
|
|
// This is how we implement our drop behavior.
|
|
if let Some(drop_check) = custom_value.as_any().downcast_ref::<DropCheckValue>() {
|
|
drop_check.notify();
|
|
} else if let Some(handle) = custom_value.as_any().downcast_ref::<HandleCustomValue>() {
|
|
if let Ok(mut handles) = self.handles.lock() {
|
|
handles.remove(&handle.0);
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
serve_plugin(&CustomValuePlugin::default(), MsgPackSerializer {})
|
|
}
|