mirror of
https://github.com/nushell/nushell.git
synced 2025-05-30 19:32:46 +00:00
266 lines
7.9 KiB
Rust
266 lines
7.9 KiB
Rust
use crate::plugin::PluginError;
|
|
use crate::plugin_capnp::value;
|
|
use nu_protocol::{Span, Value};
|
|
|
|
pub(crate) fn serialize_value(value: &Value, mut builder: value::Builder) {
|
|
let value_span = match value {
|
|
Value::Nothing { span } => {
|
|
builder.set_void(());
|
|
*span
|
|
}
|
|
Value::Bool { val, span } => {
|
|
builder.set_bool(*val);
|
|
*span
|
|
}
|
|
Value::Int { val, span } => {
|
|
builder.set_int(*val);
|
|
*span
|
|
}
|
|
Value::Float { val, span } => {
|
|
builder.set_float(*val);
|
|
*span
|
|
}
|
|
Value::String { val, span } => {
|
|
builder.set_string(val);
|
|
*span
|
|
}
|
|
Value::List { vals, span } => {
|
|
let mut list_builder = builder.reborrow().init_list(vals.len() as u32);
|
|
for (index, value) in vals.iter().enumerate() {
|
|
let inner_builder = list_builder.reborrow().get(index as u32);
|
|
serialize_value(value, inner_builder);
|
|
}
|
|
|
|
*span
|
|
}
|
|
_ => {
|
|
// If there is the need to pass other type of value to the plugin
|
|
// we have to define the encoding for that object in this match
|
|
Span::unknown()
|
|
}
|
|
};
|
|
|
|
let mut span = builder.reborrow().init_span();
|
|
span.set_start(value_span.start as u64);
|
|
span.set_end(value_span.end as u64);
|
|
}
|
|
|
|
pub(crate) fn deserialize_value(reader: value::Reader) -> Result<Value, PluginError> {
|
|
let span_reader = reader
|
|
.get_span()
|
|
.map_err(|e| PluginError::DecodingError(e.to_string()))?;
|
|
|
|
let span = Span {
|
|
start: span_reader.get_start() as usize,
|
|
end: span_reader.get_end() as usize,
|
|
};
|
|
|
|
match reader.which() {
|
|
Ok(value::Void(())) => Ok(Value::Nothing { span }),
|
|
Ok(value::Bool(val)) => Ok(Value::Bool { val, span }),
|
|
Ok(value::Int(val)) => Ok(Value::Int { val, span }),
|
|
Ok(value::Float(val)) => Ok(Value::Float { val, span }),
|
|
Ok(value::String(val)) => {
|
|
let string = val
|
|
.map_err(|e| PluginError::DecodingError(e.to_string()))?
|
|
.to_string();
|
|
Ok(Value::String { val: string, span })
|
|
}
|
|
Ok(value::List(vals)) => {
|
|
let values = vals.map_err(|e| PluginError::DecodingError(e.to_string()))?;
|
|
|
|
let values_list = values
|
|
.iter()
|
|
.map(deserialize_value)
|
|
.collect::<Result<Vec<Value>, PluginError>>()?;
|
|
|
|
Ok(Value::List {
|
|
vals: values_list,
|
|
span,
|
|
})
|
|
}
|
|
Err(capnp::NotInSchema(_)) => Ok(Value::Nothing {
|
|
span: Span::unknown(),
|
|
}),
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use capnp::serialize_packed;
|
|
use nu_protocol::{Span, Value};
|
|
|
|
pub fn write_buffer(
|
|
value: &Value,
|
|
writer: &mut impl std::io::Write,
|
|
) -> Result<(), PluginError> {
|
|
let mut message = ::capnp::message::Builder::new_default();
|
|
|
|
let mut builder = message.init_root::<value::Builder>();
|
|
|
|
serialize_value(value, builder.reborrow());
|
|
|
|
serialize_packed::write_message(writer, &message)
|
|
.map_err(|e| PluginError::EncodingError(e.to_string()))
|
|
}
|
|
|
|
pub fn read_buffer(reader: &mut impl std::io::BufRead) -> Result<Value, PluginError> {
|
|
let message_reader =
|
|
serialize_packed::read_message(reader, ::capnp::message::ReaderOptions::new()).unwrap();
|
|
|
|
let reader = message_reader
|
|
.get_root::<value::Reader>()
|
|
.map_err(|e| PluginError::DecodingError(e.to_string()))?;
|
|
|
|
deserialize_value(reader.reborrow())
|
|
}
|
|
|
|
#[test]
|
|
fn value_round_trip() {
|
|
let values = [
|
|
Value::Bool {
|
|
val: false,
|
|
span: Span { start: 1, end: 20 },
|
|
},
|
|
Value::Int {
|
|
val: 10,
|
|
span: Span { start: 2, end: 30 },
|
|
},
|
|
Value::Float {
|
|
val: 10.0,
|
|
span: Span { start: 3, end: 40 },
|
|
},
|
|
Value::String {
|
|
val: "a string".into(),
|
|
span: Span { start: 4, end: 50 },
|
|
},
|
|
];
|
|
|
|
for value in values {
|
|
let mut buffer: Vec<u8> = Vec::new();
|
|
write_buffer(&value, &mut buffer).expect("unable to serialize message");
|
|
let returned_value =
|
|
read_buffer(&mut buffer.as_slice()).expect("unable to deserialize message");
|
|
|
|
assert_eq!(value, returned_value)
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn value_nothing_round_trip() {
|
|
// Since nothing doesn't implement PartialOrd, we only compare that the
|
|
// encoded and decoded spans are correct
|
|
let value = Value::Nothing {
|
|
span: Span { start: 0, end: 10 },
|
|
};
|
|
|
|
let mut buffer: Vec<u8> = Vec::new();
|
|
write_buffer(&value, &mut buffer).expect("unable to serialize message");
|
|
let returned_value =
|
|
read_buffer(&mut buffer.as_slice()).expect("unable to deserialize message");
|
|
|
|
assert_eq!(
|
|
value.span().expect("span"),
|
|
returned_value.span().expect("span")
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn list_round_trip() {
|
|
let values = vec![
|
|
Value::Bool {
|
|
val: false,
|
|
span: Span { start: 1, end: 20 },
|
|
},
|
|
Value::Int {
|
|
val: 10,
|
|
span: Span { start: 2, end: 30 },
|
|
},
|
|
Value::Float {
|
|
val: 10.0,
|
|
span: Span { start: 3, end: 40 },
|
|
},
|
|
Value::String {
|
|
val: "a string".into(),
|
|
span: Span { start: 4, end: 50 },
|
|
},
|
|
];
|
|
|
|
let value = Value::List {
|
|
vals: values,
|
|
span: Span { start: 1, end: 10 },
|
|
};
|
|
|
|
let mut buffer: Vec<u8> = Vec::new();
|
|
write_buffer(&value, &mut buffer).expect("unable to serialize message");
|
|
let returned_value =
|
|
read_buffer(&mut buffer.as_slice()).expect("unable to deserialize message");
|
|
|
|
assert_eq!(
|
|
value.span().expect("span"),
|
|
returned_value.span().expect("span")
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn nested_list_round_trip() {
|
|
let inner_values = vec![
|
|
Value::Bool {
|
|
val: false,
|
|
span: Span { start: 1, end: 20 },
|
|
},
|
|
Value::Int {
|
|
val: 10,
|
|
span: Span { start: 2, end: 30 },
|
|
},
|
|
Value::Float {
|
|
val: 10.0,
|
|
span: Span { start: 3, end: 40 },
|
|
},
|
|
Value::String {
|
|
val: "inner string".into(),
|
|
span: Span { start: 4, end: 50 },
|
|
},
|
|
];
|
|
|
|
let values = vec![
|
|
Value::Bool {
|
|
val: true,
|
|
span: Span { start: 1, end: 20 },
|
|
},
|
|
Value::Int {
|
|
val: 66,
|
|
span: Span { start: 2, end: 30 },
|
|
},
|
|
Value::Float {
|
|
val: 66.6,
|
|
span: Span { start: 3, end: 40 },
|
|
},
|
|
Value::String {
|
|
val: "a string".into(),
|
|
span: Span { start: 4, end: 50 },
|
|
},
|
|
Value::List {
|
|
vals: inner_values,
|
|
span: Span { start: 5, end: 60 },
|
|
},
|
|
];
|
|
|
|
let value = Value::List {
|
|
vals: values,
|
|
span: Span { start: 1, end: 10 },
|
|
};
|
|
|
|
let mut buffer: Vec<u8> = Vec::new();
|
|
write_buffer(&value, &mut buffer).expect("unable to serialize message");
|
|
let returned_value =
|
|
read_buffer(&mut buffer.as_slice()).expect("unable to deserialize message");
|
|
|
|
assert_eq!(
|
|
value.span().expect("span"),
|
|
returned_value.span().expect("span")
|
|
)
|
|
}
|
|
}
|