use std::path::PathBuf;
use nu_protocol::{CustomValue, ShellError, Value};
use serde::Serialize;
use crate::plugin::{call_plugin, create_command, get_plugin_encoding};
use super::{PluginCall, PluginData, PluginResponse};
#[derive(Clone, Debug, Serialize)]
pub struct PluginCustomValue {
pub name: String,
pub data: Vec<u8>,
pub filename: PathBuf,
#[serde(skip)]
pub shell: Option<PathBuf>,
#[serde(skip)]
pub source: String,
}
impl CustomValue for PluginCustomValue {
fn clone_value(&self, span: nu_protocol::Span) -> nu_protocol::Value {
Value::custom_value(Box::new(self.clone()), span)
}
fn value_string(&self) -> String {
self.name.clone()
}
fn to_base_value(
&self,
span: nu_protocol::Span,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
let mut plugin_cmd = create_command(&self.filename, self.shell.as_deref());
let mut child = plugin_cmd.spawn().map_err(|err| ShellError::GenericError {
error: format!(
"Unable to spawn plugin for {} to get base value",
self.source
),
msg: format!("{err}"),
span: Some(span),
help: None,
inner: vec![],
})?;
let plugin_call = PluginCall::CollapseCustomValue(PluginData {
data: self.data.clone(),
span,
});
let encoding = {
let stdout_reader = match &mut child.stdout {
Some(out) => out,
None => {
return Err(ShellError::PluginFailedToLoad {
msg: "Plugin missing stdout reader".into(),
})
}
};
get_plugin_encoding(stdout_reader)?
};
let response = call_plugin(&mut child, plugin_call, &encoding, span).map_err(|err| {
ShellError::GenericError {
error: format!(
"Unable to decode call for {} to get base value",
self.source
),
msg: format!("{err}"),
span: Some(span),
help: None,
inner: vec![],
}
});
let value = match response {
Ok(PluginResponse::Value(value)) => Ok(*value),
Ok(PluginResponse::PluginData(..)) => Err(ShellError::GenericError {
error: "Plugin misbehaving".into(),
msg: "Plugin returned custom data as a response to a collapse call".into(),
span: Some(span),
help: None,
inner: vec![],
}),
Ok(PluginResponse::Error(err)) => Err(err.into()),
Ok(PluginResponse::Signature(..)) => Err(ShellError::GenericError {
error: "Plugin missing value".into(),
msg: "Received a signature from plugin instead of value".into(),
span: Some(span),
help: None,
inner: vec![],
}),
Err(err) => Err(err),
};
let _ = child.wait();
value
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn typetag_name(&self) -> &'static str {
"PluginCustomValue"
}
fn typetag_deserialize(&self) {
unimplemented!("typetag_deserialize")
}
}