mirror of
https://github.com/nushell/nushell.git
synced 2025-07-08 02:17:22 +02:00
Remove serde derive for ShellError
, replace via LabeledError
(#12319)
# Description This changes the interface for plugins to always represent errors as `LabeledError`s. This is good for altlang plugins, as it would suck for them to have to implement and track `ShellError`. We save a lot of generated code from the `ShellError` serde impl too, so `nu` and plugins get to have a smaller binary size. Reduces the release binary size by 1.2 MiB on my build configuration. # User-Facing Changes - Changes plugin protocol. `ShellError` no longer serialized. - `ShellError` serialize output is different - `ShellError` no longer deserializes to exactly the same value as serialized # Tests + Formatting - 🟢 `toolkit fmt` - 🟢 `toolkit clippy` - 🟢 `toolkit test` - 🟢 `toolkit test stdlib` # After Submitting - [ ] Document in plugin protocol reference
This commit is contained in:
@ -3,13 +3,14 @@ use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::{
|
||||
ast::Operator, engine::StateWorkingSet, format_error, ParseError, Span, Spanned, Value,
|
||||
ast::Operator, engine::StateWorkingSet, format_error, LabeledError, ParseError, Span, Spanned,
|
||||
Value,
|
||||
};
|
||||
|
||||
/// The fundamental error type for the evaluation engine. These cases represent different kinds of errors
|
||||
/// the evaluator might face, along with helpful spans to label. An error renderer will take this error value
|
||||
/// and pass it into an error viewer to display to the user.
|
||||
#[derive(Debug, Clone, Error, Diagnostic, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Debug, Clone, Error, Diagnostic, PartialEq)]
|
||||
pub enum ShellError {
|
||||
/// An operator received two arguments of incompatible types.
|
||||
///
|
||||
@ -1407,6 +1408,75 @@ impl From<super::LabeledError> for ShellError {
|
||||
}
|
||||
}
|
||||
|
||||
/// `ShellError` always serializes as [`LabeledError`].
|
||||
impl Serialize for ShellError {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
LabeledError::from_diagnostic(self).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
/// `ShellError` always deserializes as if it were [`LabeledError`], resulting in a
|
||||
/// [`ShellError::LabeledError`] variant.
|
||||
impl<'de> Deserialize<'de> for ShellError {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
LabeledError::deserialize(deserializer).map(ShellError::from)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_code(err: &ShellError) -> Option<String> {
|
||||
err.code().map(|code| code.to_string())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shell_error_serialize_roundtrip() {
|
||||
// Ensure that we can serialize and deserialize `ShellError`, and check that it basically would
|
||||
// look the same
|
||||
let original_error = ShellError::CantConvert {
|
||||
span: Span::new(100, 200),
|
||||
to_type: "Foo".into(),
|
||||
from_type: "Bar".into(),
|
||||
help: Some("this is a test".into()),
|
||||
};
|
||||
println!("orig_error = {:#?}", original_error);
|
||||
|
||||
let serialized =
|
||||
serde_json::to_string_pretty(&original_error).expect("serde_json::to_string_pretty failed");
|
||||
println!("serialized = {}", serialized);
|
||||
|
||||
let deserialized: ShellError =
|
||||
serde_json::from_str(&serialized).expect("serde_json::from_str failed");
|
||||
println!("deserialized = {:#?}", deserialized);
|
||||
|
||||
// We don't expect the deserialized error to be the same as the original error, but its miette
|
||||
// properties should be comparable
|
||||
assert_eq!(original_error.to_string(), deserialized.to_string());
|
||||
|
||||
assert_eq!(
|
||||
original_error.code().map(|c| c.to_string()),
|
||||
deserialized.code().map(|c| c.to_string())
|
||||
);
|
||||
|
||||
let orig_labels = original_error
|
||||
.labels()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
let deser_labels = deserialized
|
||||
.labels()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(orig_labels, deser_labels);
|
||||
|
||||
assert_eq!(
|
||||
original_error.help().map(|c| c.to_string()),
|
||||
deserialized.help().map(|c| c.to_string())
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user