From 3ec53e544c0fc1d62c3b39567c12d682e2694741 Mon Sep 17 00:00:00 2001 From: WindSoilder Date: Thu, 1 Sep 2022 06:33:30 +0800 Subject: [PATCH] remove capnp protocol for plugin... (#6421) * remove capnp protocol for plugin... * remove relative doc --- Cargo.lock | 7 - .../nu-command/src/core_commands/register.rs | 2 +- crates/nu-parser/src/parse_keywords.rs | 2 +- crates/nu-plugin/Cargo.toml | 1 - crates/nu-plugin/README.md | 17 - crates/nu-plugin/benches/encoder_benchmark.rs | 4 +- crates/nu-plugin/src/lib.rs | 7 +- .../nu-plugin/src/serializers/capnp/call.rs | 222 -------- .../src/serializers/capnp/call_input.rs | 113 ---- crates/nu-plugin/src/serializers/capnp/mod.rs | 49 -- .../src/serializers/capnp/plugin_call.rs | 519 ------------------ .../src/serializers/capnp/plugin_data.rs | 79 --- .../src/serializers/capnp/schema/plugin.capnp | 170 ------ .../src/serializers/capnp/signature.rs | 428 --------------- .../nu-plugin/src/serializers/capnp/value.rs | 375 ------------- crates/nu-plugin/src/serializers/mod.rs | 8 - crates/nu_plugin_example/src/main.rs | 2 +- 17 files changed, 6 insertions(+), 1999 deletions(-) delete mode 100644 crates/nu-plugin/src/serializers/capnp/call.rs delete mode 100644 crates/nu-plugin/src/serializers/capnp/call_input.rs delete mode 100644 crates/nu-plugin/src/serializers/capnp/mod.rs delete mode 100644 crates/nu-plugin/src/serializers/capnp/plugin_call.rs delete mode 100644 crates/nu-plugin/src/serializers/capnp/plugin_data.rs delete mode 100644 crates/nu-plugin/src/serializers/capnp/schema/plugin.capnp delete mode 100644 crates/nu-plugin/src/serializers/capnp/signature.rs delete mode 100644 crates/nu-plugin/src/serializers/capnp/value.rs diff --git a/Cargo.lock b/Cargo.lock index 0c9437456f..b1ae71ccca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -499,12 +499,6 @@ dependencies = [ "zip", ] -[[package]] -name = "capnp" -version = "0.14.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82efa3b0ab5e7e32b786334b052560ec0094135f906975d7481651b9ecf31a6a" - [[package]] name = "cast" version = "0.3.0" @@ -2820,7 +2814,6 @@ version = "0.67.1" dependencies = [ "bincode", "byte-order", - "capnp", "criterion", "nu-engine", "nu-protocol", diff --git a/crates/nu-command/src/core_commands/register.rs b/crates/nu-command/src/core_commands/register.rs index a6d449c055..e0750735c1 100644 --- a/crates/nu-command/src/core_commands/register.rs +++ b/crates/nu-command/src/core_commands/register.rs @@ -24,7 +24,7 @@ impl Command for Register { .required_named( "encoding", SyntaxShape::String, - "Encoding used to communicate with plugin. Options: [capnp, json, msgpack]", + "Encoding used to communicate with plugin. Options: [json, msgpack]", Some('e'), ) .optional( diff --git a/crates/nu-parser/src/parse_keywords.rs b/crates/nu-parser/src/parse_keywords.rs index 1360239463..50ee95fd1f 100644 --- a/crates/nu-parser/src/parse_keywords.rs +++ b/crates/nu-parser/src/parse_keywords.rs @@ -3065,7 +3065,7 @@ pub fn parse_register( ParseError::IncorrectValue( "wrong encoding".into(), expr.span, - "Encodings available: capnp, json, and msgpack".into(), + "Encodings available: json, and msgpack".into(), ) }) }) diff --git a/crates/nu-plugin/Cargo.toml b/crates/nu-plugin/Cargo.toml index b2ab8498e4..31fc2c8741 100644 --- a/crates/nu-plugin/Cargo.toml +++ b/crates/nu-plugin/Cargo.toml @@ -9,7 +9,6 @@ version = "0.67.1" [dependencies] bincode = "1.3.3" -capnp = "0.14.3" nu-protocol = { path = "../nu-protocol", version = "0.67.1" } nu-engine = { path = "../nu-engine", version = "0.67.1" } serde = {version = "1.0.143", features = ["derive"]} diff --git a/crates/nu-plugin/README.md b/crates/nu-plugin/README.md index d7c5cf44dc..a7d9663b9d 100644 --- a/crates/nu-plugin/README.md +++ b/crates/nu-plugin/README.md @@ -1,22 +1,5 @@ # nu-plugin -## Updating Cap'n Proto schema - -When modifying a protocol's struct that is used in plugins (such as Signature), you need to update the capnproto schema file and recompile it into the Rust source code. -The steps are as follows: -1. Change `src/serializers/capnp/schema/plugin.capnp` as necessary -2. Install `capnp` tool (it's a C++ binary, commonly available in package managers) -3. Install Rust support for `capnp` called `capnpc-rust`: - 1. `git clone https://github.com/capnproto/capnproto-rust` somewhere - 2. `cd capnproto-rust/capnpc` - 3. `cargo install --path=.` -4. Then, call `capnp compile -orust plugin.capnp` (change path as necessary) -5. The result should be `plugin_capnp.rs` file: Use it to replace the old `src/plugin_capnp.rs`. -6. It needs to be autoformatted (`cargo fmt --all`) -7. Modify the serialize/deserialize functions. Check the following PRs for details: - * https://github.com/nushell/nushell/pull/4980 - * https://github.com/nushell/nushell/pull/4920 - ## Benchmark Here is a simple benchmark for different protocol for encoding/decoding nushell table, with different rows and columns. You can simply run `cargo bench` to run benchmark. diff --git a/crates/nu-plugin/benches/encoder_benchmark.rs b/crates/nu-plugin/benches/encoder_benchmark.rs index 06b9de738e..acc026f0f9 100644 --- a/crates/nu-plugin/benches/encoder_benchmark.rs +++ b/crates/nu-plugin/benches/encoder_benchmark.rs @@ -29,7 +29,7 @@ fn bench_encoding(c: &mut Criterion) { (10000, 15), ]; for (row_cnt, col_cnt) in test_cnt_pairs.into_iter() { - for fmt in ["capnp", "json", "msgpack"] { + for fmt in ["json", "msgpack"] { group.bench_function(&format!("{fmt} encode {row_cnt} * {col_cnt}"), |b| { let mut res = vec![]; let test_data = PluginResponse::Value(Box::new(new_test_data(row_cnt, col_cnt))); @@ -55,7 +55,7 @@ fn bench_decoding(c: &mut Criterion) { (10000, 15), ]; for (row_cnt, col_cnt) in test_cnt_pairs.into_iter() { - for fmt in ["capnp", "json", "msgpack"] { + for fmt in ["json", "msgpack"] { group.bench_function(&format!("{fmt} decode for {row_cnt} * {col_cnt}"), |b| { let mut res = vec![]; let test_data = PluginResponse::Value(Box::new(new_test_data(row_cnt, col_cnt))); diff --git a/crates/nu-plugin/src/lib.rs b/crates/nu-plugin/src/lib.rs index bdb321ed67..bec0fb536f 100644 --- a/crates/nu-plugin/src/lib.rs +++ b/crates/nu-plugin/src/lib.rs @@ -2,11 +2,6 @@ mod plugin; mod protocol; mod serializers; -#[allow(dead_code)] -mod plugin_capnp; - pub use plugin::{get_signature, serve_plugin, Plugin, PluginDeclaration}; pub use protocol::{EvaluatedCall, LabeledError, PluginData, PluginResponse}; -pub use serializers::{ - capnp::CapnpSerializer, json::JsonSerializer, msgpack::MsgPackSerializer, EncodingType, -}; +pub use serializers::{json::JsonSerializer, msgpack::MsgPackSerializer, EncodingType}; diff --git a/crates/nu-plugin/src/serializers/capnp/call.rs b/crates/nu-plugin/src/serializers/capnp/call.rs deleted file mode 100644 index 264c92c9b2..0000000000 --- a/crates/nu-plugin/src/serializers/capnp/call.rs +++ /dev/null @@ -1,222 +0,0 @@ -use super::value; -use crate::{plugin_capnp::evaluated_call, EvaluatedCall}; -use nu_protocol::{ShellError, Span, Spanned, Value}; - -pub(crate) fn serialize_call( - call: &EvaluatedCall, - mut builder: evaluated_call::Builder, -) -> Result<(), ShellError> { - let mut head = builder.reborrow().init_head(); - head.set_start(call.head.start as u64); - head.set_end(call.head.end as u64); - - serialize_positional(&call.positional, builder.reborrow()); - serialize_named(&call.named, builder)?; - - Ok(()) -} - -fn serialize_positional(positional: &[Value], mut builder: evaluated_call::Builder) { - let mut positional_builder = builder.reborrow().init_positional(positional.len() as u32); - - for (index, value) in positional.iter().enumerate() { - value::serialize_value(value, positional_builder.reborrow().get(index as u32)) - } -} - -fn serialize_named( - named: &[(Spanned, Option)], - mut builder: evaluated_call::Builder, -) -> Result<(), ShellError> { - let mut named_builder = builder - .reborrow() - .init_named() - .init_entries(named.len() as u32); - - for (index, (key, expression)) in named.iter().enumerate() { - let mut entry_builder = named_builder.reborrow().get(index as u32); - entry_builder - .reborrow() - .set_key(key.item.as_str()) - .map_err(|e| ShellError::PluginFailedToEncode(e.to_string()))?; - - if let Some(value) = expression { - let value_builder = entry_builder.init_value(); - value::serialize_value(value, value_builder); - } - } - - Ok(()) -} - -pub(crate) fn deserialize_call( - reader: evaluated_call::Reader, -) -> Result { - let head_reader = reader - .get_head() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let head = Span { - start: head_reader.get_start() as usize, - end: head_reader.get_end() as usize, - }; - - let positional = deserialize_positionals(head, reader)?; - let named = deserialize_named(head, reader)?; - - Ok(EvaluatedCall { - head, - positional, - named, - }) -} - -fn deserialize_positionals( - span: Span, - reader: evaluated_call::Reader, -) -> Result, ShellError> { - let positional_reader = reader - .get_positional() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - positional_reader - .iter() - .map(move |x| value::deserialize_value(x, span)) - .collect() -} - -type NamedList = Vec<(Spanned, Option)>; - -fn deserialize_named(span: Span, reader: evaluated_call::Reader) -> Result { - let named_reader = reader - .get_named() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let entries_list = named_reader - .get_entries() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let mut entries: Vec<(Spanned, Option)> = - Vec::with_capacity(entries_list.len() as usize); - - for entry_reader in entries_list { - let item = entry_reader - .get_key() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))? - .to_string(); - - let value = if entry_reader.has_value() { - let value_reader = entry_reader - .get_value() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let value = value::deserialize_value(value_reader, span) - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - Some(value) - } else { - None - }; - - let key = Spanned { item, span }; - - entries.push((key, value)) - } - - Ok(entries) -} - -#[cfg(test)] -mod tests { - use capnp::serialize; - use core::panic; - - use super::*; - use nu_protocol::{Span, Spanned, Value}; - - fn write_buffer( - call: &EvaluatedCall, - writer: &mut impl std::io::Write, - ) -> Result<(), ShellError> { - let mut message = ::capnp::message::Builder::new_default(); - - let builder = message.init_root::(); - serialize_call(call, builder)?; - - serialize::write_message(writer, &message) - .map_err(|e| ShellError::PluginFailedToLoad(e.to_string())) - } - - fn read_buffer(reader: &mut impl std::io::BufRead) -> Result { - let message_reader = - serialize::read_message(reader, ::capnp::message::ReaderOptions::new()).unwrap(); - - let reader = message_reader - .get_root::() - .map_err(|e| ShellError::PluginFailedToLoad(e.to_string()))?; - - deserialize_call(reader) - } - - #[test] - fn call_round_trip() { - let call = EvaluatedCall { - head: Span { start: 0, end: 10 }, - positional: vec![ - Value::Float { - val: 1.0, - span: Span { start: 0, end: 10 }, - }, - Value::String { - val: "something".into(), - span: Span { start: 0, end: 10 }, - }, - ], - named: vec![ - ( - Spanned { - item: "name".to_string(), - span: Span { start: 0, end: 10 }, - }, - Some(Value::Float { - val: 1.0, - span: Span { start: 0, end: 10 }, - }), - ), - ( - Spanned { - item: "flag".to_string(), - span: Span { start: 0, end: 10 }, - }, - None, - ), - ], - }; - - let mut buffer: Vec = Vec::new(); - write_buffer(&call, &mut buffer).expect("unable to serialize message"); - let returned_call = read_buffer(&mut buffer.as_slice()).expect("unable to read buffer"); - - assert_eq!(call.head, returned_call.head); - assert_eq!(call.positional.len(), returned_call.positional.len()); - - call.positional - .iter() - .zip(returned_call.positional.iter()) - .for_each(|(lhs, rhs)| assert_eq!(lhs, rhs)); - - call.named - .iter() - .zip(returned_call.named.iter()) - .for_each(|(lhs, rhs)| { - // Comparing the keys - assert_eq!(lhs.0.item, rhs.0.item); - - match (&lhs.1, &rhs.1) { - (None, None) => {} - (Some(a), Some(b)) => assert_eq!(a, b), - _ => panic!("not matching values"), - } - }); - } -} diff --git a/crates/nu-plugin/src/serializers/capnp/call_input.rs b/crates/nu-plugin/src/serializers/capnp/call_input.rs deleted file mode 100644 index bc20a0d9bd..0000000000 --- a/crates/nu-plugin/src/serializers/capnp/call_input.rs +++ /dev/null @@ -1,113 +0,0 @@ -use super::{plugin_data, value}; -use crate::{plugin_capnp::call_input, protocol::CallInput}; -use nu_protocol::{ShellError, Span}; - -pub(crate) fn serialize_call_input(call_input: &CallInput, builder: call_input::Builder) { - match call_input { - CallInput::Value(value) => { - value::serialize_value(value, builder.init_value()); - } - CallInput::Data(plugin_data) => { - let builder = builder.init_plugin_data(); - - plugin_data::serialize_plugin_data(plugin_data, builder); - } - }; -} - -pub(crate) fn deserialize_call_input(reader: call_input::Reader) -> Result { - match reader.which() { - Err(capnp::NotInSchema(_)) => Err(ShellError::PluginFailedToDecode( - "value not in schema".into(), - )), - Ok(call_input::Value(value_reader)) => { - let value_reader = - value_reader.map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let span_reader = value_reader - .get_span() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let span = Span { - start: span_reader.get_start() as usize, - end: span_reader.get_end() as usize, - }; - - Ok(CallInput::Value(value::deserialize_value( - value_reader, - span, - )?)) - } - Ok(call_input::PluginData(plugin_data_reader)) => { - let plugin_data_reader = - plugin_data_reader.map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let plugin_data = plugin_data::deserialize_plugin_data(plugin_data_reader)?; - - Ok(CallInput::Data(plugin_data)) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::protocol::{CallInput, PluginData}; - use capnp::serialize; - use nu_protocol::{Span, Value}; - - pub fn write_buffer( - call_input: &CallInput, - writer: &mut impl std::io::Write, - ) -> Result<(), ShellError> { - let mut message = ::capnp::message::Builder::new_default(); - - let mut builder = message.init_root::(); - - serialize_call_input(call_input, builder.reborrow()); - - serialize::write_message(writer, &message) - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string())) - } - - pub fn read_buffer(reader: &mut impl std::io::BufRead) -> Result { - let message_reader = - serialize::read_message(reader, ::capnp::message::ReaderOptions::new()).unwrap(); - - let reader = message_reader - .get_root::() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - deserialize_call_input(reader.reborrow()) - } - - #[test] - fn callinput_value_round_trip() { - let call_input = CallInput::Value(Value::String { - val: "abc".to_string(), - span: Span { start: 1, end: 20 }, - }); - - let mut buffer: Vec = Vec::new(); - write_buffer(&call_input, &mut buffer).expect("unable to serialize message"); - let returned_call_input = - read_buffer(&mut buffer.as_slice()).expect("unable to deserialize message"); - - assert_eq!(call_input, returned_call_input) - } - - #[test] - fn callinput_data_round_trip() { - let call_input = CallInput::Data(PluginData { - data: vec![1, 2, 3, 4, 5, 6, 7], - span: Span { start: 1, end: 20 }, - }); - - let mut buffer: Vec = Vec::new(); - write_buffer(&call_input, &mut buffer).expect("unable to serialize message"); - let returned_call_input = - read_buffer(&mut buffer.as_slice()).expect("unable to deserialize message"); - - assert_eq!(call_input, returned_call_input) - } -} diff --git a/crates/nu-plugin/src/serializers/capnp/mod.rs b/crates/nu-plugin/src/serializers/capnp/mod.rs deleted file mode 100644 index 08e7d529f0..0000000000 --- a/crates/nu-plugin/src/serializers/capnp/mod.rs +++ /dev/null @@ -1,49 +0,0 @@ -mod call; -mod call_input; -mod plugin_call; -mod plugin_data; -mod signature; -mod value; - -use nu_protocol::ShellError; - -use crate::{plugin::PluginEncoder, protocol::PluginResponse}; - -#[derive(Clone, Debug)] -pub struct CapnpSerializer; - -impl PluginEncoder for CapnpSerializer { - fn name(&self) -> &str { - "Capnp Serializer" - } - - fn encode_call( - &self, - plugin_call: &crate::protocol::PluginCall, - writer: &mut impl std::io::Write, - ) -> Result<(), nu_protocol::ShellError> { - plugin_call::encode_call(plugin_call, writer) - } - - fn decode_call( - &self, - reader: &mut impl std::io::BufRead, - ) -> Result { - plugin_call::decode_call(reader) - } - - fn encode_response( - &self, - plugin_response: &PluginResponse, - writer: &mut impl std::io::Write, - ) -> Result<(), ShellError> { - plugin_call::encode_response(plugin_response, writer) - } - - fn decode_response( - &self, - reader: &mut impl std::io::BufRead, - ) -> Result { - plugin_call::decode_response(reader) - } -} diff --git a/crates/nu-plugin/src/serializers/capnp/plugin_call.rs b/crates/nu-plugin/src/serializers/capnp/plugin_call.rs deleted file mode 100644 index 8bdc14234a..0000000000 --- a/crates/nu-plugin/src/serializers/capnp/plugin_call.rs +++ /dev/null @@ -1,519 +0,0 @@ -use super::signature::deserialize_signature; -use super::{call, call_input, plugin_data, signature, value}; -use crate::plugin_capnp::{plugin_call, plugin_response}; -use crate::protocol::{CallInfo, LabeledError, PluginCall, PluginResponse}; -use capnp::serialize; -use nu_protocol::{ShellError, Signature, Span}; - -pub fn encode_call( - plugin_call: &PluginCall, - writer: &mut impl std::io::Write, -) -> Result<(), ShellError> { - let mut message = ::capnp::message::Builder::new_default(); - - let mut builder = message.init_root::(); - - match &plugin_call { - PluginCall::Signature => builder.set_signature(()), - PluginCall::CallInfo(call_info) => { - let mut call_info_builder = builder.reborrow().init_call_info(); - - // Serializing name from the call - call_info_builder.set_name(call_info.name.as_str()); - - // Serializing argument information from the call - let call_builder = call_info_builder - .reborrow() - .get_call() - .map_err(|e| ShellError::PluginFailedToEncode(e.to_string()))?; - - call::serialize_call(&call_info.call, call_builder) - .map_err(|e| ShellError::PluginFailedToEncode(e.to_string()))?; - - // Serializing the input value from the call info - let call_input_builder = call_info_builder - .reborrow() - .get_input() - .map_err(|e| ShellError::PluginFailedToEncode(e.to_string()))?; - - call_input::serialize_call_input(&call_info.input, call_input_builder); - } - PluginCall::CollapseCustomValue(plugin_data) => { - let builder = builder.init_collapse_custom_value(); - - plugin_data::serialize_plugin_data(plugin_data, builder); - } - }; - - serialize::write_message(writer, &message) - .map_err(|e| ShellError::PluginFailedToEncode(e.to_string())) -} - -pub fn decode_call(reader: &mut impl std::io::BufRead) -> Result { - let message_reader = serialize::read_message(reader, ::capnp::message::ReaderOptions::new()) - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let reader = message_reader - .get_root::() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - match reader.which() { - Err(capnp::NotInSchema(_)) => Err(ShellError::PluginFailedToDecode( - "value not in schema".into(), - )), - Ok(plugin_call::Signature(())) => Ok(PluginCall::Signature), - Ok(plugin_call::CallInfo(reader)) => { - let reader = reader.map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let name = reader - .get_name() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let call_reader = reader - .get_call() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let call = call::deserialize_call(call_reader)?; - - let input_reader = reader - .get_input() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let input = call_input::deserialize_call_input(input_reader)?; - - Ok(PluginCall::CallInfo(CallInfo { - name: name.to_string(), - call, - input, - })) - } - Ok(plugin_call::CollapseCustomValue(reader)) => { - let reader = reader.map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let plugin_data = plugin_data::deserialize_plugin_data(reader)?; - - Ok(PluginCall::CollapseCustomValue(plugin_data)) - } - } -} - -pub fn encode_response( - plugin_response: &PluginResponse, - writer: &mut impl std::io::Write, -) -> Result<(), ShellError> { - let mut message = ::capnp::message::Builder::new_default(); - - let mut builder = message.init_root::(); - - match &plugin_response { - PluginResponse::Error(msg) => { - let mut error_builder = builder.reborrow().init_error(); - error_builder.set_label(&msg.label); - error_builder.set_msg(&msg.msg); - - if let Some(span) = msg.span { - let mut span_builder = error_builder.reborrow().init_span(); - span_builder.set_start(span.start as u64); - span_builder.set_end(span.end as u64); - } - } - PluginResponse::Signature(signatures) => { - let mut signature_list_builder = - builder.reborrow().init_signature(signatures.len() as u32); - - for (index, signature) in signatures.iter().enumerate() { - let signature_builder = signature_list_builder.reborrow().get(index as u32); - signature::serialize_signature(signature, signature_builder) - } - } - PluginResponse::Value(val) => { - let value_builder = builder.reborrow().init_value(); - value::serialize_value(val, value_builder); - } - PluginResponse::PluginData(name, plugin_data) => { - let mut plugin_data_builder = builder.reborrow().init_plugin_data(); - - plugin_data_builder.set_name(name); - plugin_data::serialize_plugin_data(plugin_data, plugin_data_builder.init_data()); - } - }; - - serialize::write_message(writer, &message) - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string())) -} - -pub fn decode_response(reader: &mut impl std::io::BufRead) -> Result { - let message_reader = serialize::read_message(reader, ::capnp::message::ReaderOptions::new()) - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let reader = message_reader - .get_root::() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - match reader.which() { - Err(capnp::NotInSchema(_)) => Err(ShellError::PluginFailedToDecode( - "value not in schema".into(), - )), - Ok(plugin_response::Error(reader)) => { - let reader = reader.map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let msg = reader - .get_msg() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let label = reader - .get_label() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let span = if reader.has_span() { - let span = reader - .get_span() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - Some(Span { - start: span.get_start() as usize, - end: span.get_end() as usize, - }) - } else { - None - }; - - let error = LabeledError { - label: label.into(), - msg: msg.into(), - span, - }; - - Ok(PluginResponse::Error(error)) - } - Ok(plugin_response::Signature(reader)) => { - let reader = reader.map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let signatures = reader - .iter() - .map(deserialize_signature) - .collect::, ShellError>>()?; - - Ok(PluginResponse::Signature(signatures)) - } - Ok(plugin_response::Value(reader)) => { - let reader = reader.map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let span = reader - .get_span() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let val = value::deserialize_value( - reader, - Span { - start: span.get_start() as usize, - end: span.get_end() as usize, - }, - ) - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - Ok(PluginResponse::Value(Box::new(val))) - } - Ok(plugin_response::PluginData(reader)) => { - let reader = reader.map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let name = reader - .get_name() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let plugin_data_reader = reader - .get_data() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - let plugin_data = plugin_data::deserialize_plugin_data(plugin_data_reader)?; - - Ok(PluginResponse::PluginData(name.to_string(), plugin_data)) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::protocol::{ - CallInput, EvaluatedCall, LabeledError, PluginCall, PluginData, PluginResponse, - }; - use nu_protocol::{Signature, Span, Spanned, SyntaxShape, Value}; - - #[test] - fn callinfo_round_trip_signature() { - let plugin_call = PluginCall::Signature; - - let mut buffer: Vec = Vec::new(); - encode_call(&plugin_call, &mut buffer).expect("unable to serialize message"); - let returned = decode_call(&mut buffer.as_slice()).expect("unable to deserialize message"); - - match returned { - PluginCall::Signature => {} - PluginCall::CallInfo(_) => panic!("decoded into wrong value"), - PluginCall::CollapseCustomValue(_) => panic!("decoded into wrong value"), - } - } - - #[test] - fn callinfo_round_trip_callinfo() { - let name = "test".to_string(); - - let input = CallInput::Value(Value::Bool { - val: false, - span: Span { start: 1, end: 20 }, - }); - - let call = EvaluatedCall { - head: Span { start: 0, end: 10 }, - positional: vec![ - Value::Float { - val: 1.0, - span: Span { start: 0, end: 10 }, - }, - Value::String { - val: "something".into(), - span: Span { start: 0, end: 10 }, - }, - ], - named: vec![( - Spanned { - item: "name".to_string(), - span: Span { start: 0, end: 10 }, - }, - Some(Value::Float { - val: 1.0, - span: Span { start: 0, end: 10 }, - }), - )], - }; - - let plugin_call = PluginCall::CallInfo(CallInfo { - name: name.clone(), - call: call.clone(), - // Avoiding having to implement Clone on CallInput just for tests - input: match &input { - CallInput::Value(value) => CallInput::Value(value.clone()), - CallInput::Data(plugin_data) => CallInput::Data(PluginData { - data: plugin_data.data.clone(), - span: plugin_data.span, - }), - }, - }); - - let mut buffer: Vec = Vec::new(); - encode_call(&plugin_call, &mut buffer).expect("unable to serialize message"); - let returned = decode_call(&mut buffer.as_slice()).expect("unable to deserialize message"); - - match returned { - PluginCall::Signature => panic!("returned wrong call type"), - PluginCall::CallInfo(call_info) => { - assert_eq!(name, call_info.name); - assert_eq!(&input, &call_info.input); - assert_eq!(call.head, call_info.call.head); - assert_eq!(call.positional.len(), call_info.call.positional.len()); - - call.positional - .iter() - .zip(call_info.call.positional.iter()) - .for_each(|(lhs, rhs)| assert_eq!(lhs, rhs)); - - call.named - .iter() - .zip(call_info.call.named.iter()) - .for_each(|(lhs, rhs)| { - // Comparing the keys - assert_eq!(lhs.0.item, rhs.0.item); - - match (&lhs.1, &rhs.1) { - (None, None) => {} - (Some(a), Some(b)) => assert_eq!(a, b), - _ => panic!("not matching values"), - } - }); - } - PluginCall::CollapseCustomValue(_) => panic!("returned wrong call type"), - } - } - - #[test] - fn callinfo_round_trip_collapsecustomvalue() { - let data = vec![1, 2, 3, 4, 5, 6, 7]; - let span = Span { start: 0, end: 20 }; - - let collapse_custom_value = PluginCall::CollapseCustomValue(PluginData { - data: data.clone(), - span, - }); - - let mut buffer: Vec = Vec::new(); - encode_call(&collapse_custom_value, &mut buffer).expect("unable to serialize message"); - let returned = decode_call(&mut buffer.as_slice()).expect("unable to deserialize message"); - - match returned { - PluginCall::Signature => panic!("returned wrong call type"), - PluginCall::CallInfo(_) => panic!("returned wrong call type"), - PluginCall::CollapseCustomValue(plugin_data) => { - assert_eq!(data, plugin_data.data); - assert_eq!(span, plugin_data.span); - } - } - } - - #[test] - fn response_round_trip_signature() { - let signature = Signature::build("nu-plugin") - .required("first", SyntaxShape::String, "first required") - .required("second", SyntaxShape::Int, "second required") - .required_named("first-named", SyntaxShape::String, "first named", Some('f')) - .required_named( - "second-named", - SyntaxShape::String, - "second named", - Some('s'), - ) - .rest("remaining", SyntaxShape::Int, "remaining"); - - let response = PluginResponse::Signature(vec![signature.clone()]); - - let mut buffer: Vec = Vec::new(); - encode_response(&response, &mut buffer).expect("unable to serialize message"); - let returned = - decode_response(&mut buffer.as_slice()).expect("unable to deserialize message"); - - match returned { - PluginResponse::Error(_) => panic!("returned wrong call type"), - PluginResponse::Value(_) => panic!("returned wrong call type"), - PluginResponse::PluginData(..) => panic!("returned wrong call type"), - PluginResponse::Signature(returned_signature) => { - assert!(returned_signature.len() == 1); - assert_eq!(signature.name, returned_signature[0].name); - assert_eq!(signature.usage, returned_signature[0].usage); - assert_eq!(signature.extra_usage, returned_signature[0].extra_usage); - assert_eq!(signature.is_filter, returned_signature[0].is_filter); - - signature - .required_positional - .iter() - .zip(returned_signature[0].required_positional.iter()) - .for_each(|(lhs, rhs)| assert_eq!(lhs, rhs)); - - signature - .optional_positional - .iter() - .zip(returned_signature[0].optional_positional.iter()) - .for_each(|(lhs, rhs)| assert_eq!(lhs, rhs)); - - signature - .named - .iter() - .zip(returned_signature[0].named.iter()) - .for_each(|(lhs, rhs)| assert_eq!(lhs, rhs)); - - assert_eq!( - signature.rest_positional, - returned_signature[0].rest_positional, - ); - } - } - } - - #[test] - fn response_round_trip_value() { - let value = Value::Int { - val: 10, - span: Span { start: 2, end: 30 }, - }; - - let response = PluginResponse::Value(Box::new(value.clone())); - - let mut buffer: Vec = Vec::new(); - encode_response(&response, &mut buffer).expect("unable to serialize message"); - let returned = - decode_response(&mut buffer.as_slice()).expect("unable to deserialize message"); - - match returned { - PluginResponse::Error(_) => panic!("returned wrong call type"), - PluginResponse::Signature(_) => panic!("returned wrong call type"), - PluginResponse::PluginData(..) => panic!("returned wrong call type"), - PluginResponse::Value(returned_value) => { - assert_eq!(&value, returned_value.as_ref()) - } - } - } - - #[test] - fn response_round_trip_plugin_data() { - let name = "test".to_string(); - - let data = vec![1, 2, 3, 4, 5]; - let span = Span { start: 2, end: 30 }; - - let response = PluginResponse::PluginData( - name.clone(), - PluginData { - data: data.clone(), - span, - }, - ); - - let mut buffer: Vec = Vec::new(); - encode_response(&response, &mut buffer).expect("unable to serialize message"); - let returned = - decode_response(&mut buffer.as_slice()).expect("unable to deserialize message"); - - match returned { - PluginResponse::Error(_) => panic!("returned wrong call type"), - PluginResponse::Signature(_) => panic!("returned wrong call type"), - PluginResponse::Value(_) => panic!("returned wrong call type"), - PluginResponse::PluginData(returned_name, returned_plugin_data) => { - assert_eq!(name, returned_name); - assert_eq!(data, returned_plugin_data.data); - assert_eq!(span, returned_plugin_data.span); - } - } - } - - #[test] - fn response_round_trip_error() { - let error = LabeledError { - label: "label".into(), - msg: "msg".into(), - span: Some(Span { start: 2, end: 30 }), - }; - let response = PluginResponse::Error(error.clone()); - - let mut buffer: Vec = Vec::new(); - encode_response(&response, &mut buffer).expect("unable to serialize message"); - let returned = - decode_response(&mut buffer.as_slice()).expect("unable to deserialize message"); - - match returned { - PluginResponse::Error(msg) => assert_eq!(error, msg), - PluginResponse::Signature(_) => panic!("returned wrong call type"), - PluginResponse::Value(_) => panic!("returned wrong call type"), - PluginResponse::PluginData(..) => panic!("returned wrong call type"), - } - } - - #[test] - fn response_round_trip_error_none() { - let error = LabeledError { - label: "label".into(), - msg: "msg".into(), - span: None, - }; - let response = PluginResponse::Error(error.clone()); - - let mut buffer: Vec = Vec::new(); - encode_response(&response, &mut buffer).expect("unable to serialize message"); - let returned = - decode_response(&mut buffer.as_slice()).expect("unable to deserialize message"); - - match returned { - PluginResponse::Error(msg) => assert_eq!(error, msg), - PluginResponse::Signature(_) => panic!("returned wrong call type"), - PluginResponse::Value(_) => panic!("returned wrong call type"), - PluginResponse::PluginData(..) => panic!("returned wrong call type"), - } - } -} diff --git a/crates/nu-plugin/src/serializers/capnp/plugin_data.rs b/crates/nu-plugin/src/serializers/capnp/plugin_data.rs deleted file mode 100644 index 5b007d3650..0000000000 --- a/crates/nu-plugin/src/serializers/capnp/plugin_data.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::{plugin_capnp::plugin_data, protocol::PluginData}; -use nu_protocol::{ShellError, Span}; - -pub(crate) fn serialize_plugin_data(plugin_data: &PluginData, mut builder: plugin_data::Builder) { - builder.set_data(&plugin_data.data); - - let mut span_builder = builder.init_span(); - span_builder.set_start(plugin_data.span.start as u64); - span_builder.set_end(plugin_data.span.end as u64); -} - -pub(crate) fn deserialize_plugin_data( - reader: plugin_data::Reader, -) -> Result { - let data = reader - .get_data() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let span_reader = reader - .get_span() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let span = Span { - start: span_reader.get_start() as usize, - end: span_reader.get_end() as usize, - }; - - Ok(PluginData { - data: data.to_vec(), - span, - }) -} - -#[cfg(test)] -mod tests { - use super::*; - use capnp::serialize; - use nu_protocol::Span; - - pub fn write_buffer( - plugin_data: &PluginData, - writer: &mut impl std::io::Write, - ) -> Result<(), ShellError> { - let mut message = ::capnp::message::Builder::new_default(); - - let mut builder = message.init_root::(); - - serialize_plugin_data(plugin_data, builder.reborrow()); - - serialize::write_message(writer, &message) - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string())) - } - - pub fn read_buffer(reader: &mut impl std::io::BufRead) -> Result { - let message_reader = - serialize::read_message(reader, ::capnp::message::ReaderOptions::new()).unwrap(); - - let reader = message_reader - .get_root::() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - deserialize_plugin_data(reader.reborrow()) - } - - #[test] - fn plugin_data_round_trip() { - let plugin_data = PluginData { - data: vec![1, 2, 3, 4, 5, 6, 7], - span: Span { start: 1, end: 20 }, - }; - - let mut buffer: Vec = Vec::new(); - write_buffer(&plugin_data, &mut buffer).expect("unable to serialize message"); - let returned_plugin_data = - read_buffer(&mut buffer.as_slice()).expect("unable to deserialize message"); - - assert_eq!(plugin_data, returned_plugin_data) - } -} diff --git a/crates/nu-plugin/src/serializers/capnp/schema/plugin.capnp b/crates/nu-plugin/src/serializers/capnp/schema/plugin.capnp deleted file mode 100644 index 483c3a3493..0000000000 --- a/crates/nu-plugin/src/serializers/capnp/schema/plugin.capnp +++ /dev/null @@ -1,170 +0,0 @@ -@0xb299d30dc02d72bc; -# Schema representing all the structs that are used to communicate with -# the plugins. -# This schema, together with the command capnp proto is used to generate -# the rust file that defines the serialization/deserialization objects -# required to communicate with the plugins created for nushell -# -# If you modify the schema remember to compile it to generate the corresponding -# rust file and place that file into the main nu-plugin folder. -# After compiling, you may need to run cargo fmt on the file so it passes the CI - -struct Err(T) { - union { - err @0 :Text; - ok @1 :T; - } -} - -struct Map(Key, Value) { - struct Entry { - key @0 :Key; - value @1 :Value; - } - entries @0 :List(Entry); -} - -# Main plugin structures -struct Span { - start @0 :UInt64; - end @1 :UInt64; -} - -# Resulting value from plugin -struct Value { - span @0: Span; - - union { - void @1 :Void; - bool @2 :Bool; - int @3 :Int64; - float @4 :Float64; - string @5 :Text; - list @6 :List(Value); - record @7: Record; - } -} - -struct Record { - cols @0 :List(Text); - vals @1 :List(Value); -} - -# Structs required to define the plugin signature -struct Signature { - name @0 :Text; - usage @1 :Text; - extraUsage @2 :Text; - searchTerms @3 :List(Text); - requiredPositional @4 :List(Argument); - optionalPositional @5 :List(Argument); - # Optional value. Check for existence when deserializing - rest @6 :Argument; - named @7 :List(Flag); - isFilter @8 :Bool; - category @9 :Category; -} - -enum Category { - default @0; - conversions @1; - core @2; - date @3; - env @4; - experimental @5; - filesystem @6; - filters @7; - formats @8; - math @9; - network @10; - random @11; - platform @12; - shells @13; - strings @14; - system @15; - viewers @16; - hash @17; - generators @18; -} - -struct Flag { - long @0 :Text; - # Optional value. Check for existence when deserializing (has_short) - short @1 :Text; - arg @2 :Shape; - required @3 :Bool; - desc @4 :Text; -} - -struct Argument { - name @0 :Text; - desc @1 :Text; - shape @2 :Shape; -} - -# If we require more complex signatures for the plugins this could be -# changed to a union -enum Shape { - none @0; - any @1; - string @2; - number @3; - int @4; - boolean @5; -} - -struct EvaluatedCall { - head @0: Span; - positional @1 :List(Value); - # The value in the map can be optional - # Check for existence when deserializing - named @2 :Map(Text, Value); -} - -struct PluginData { - data @0 :Data; - span @1 :Span; -} - -struct CallInput { - union { - value @0 :Value; - pluginData @1 :PluginData; - } -} - -struct CallInfo { - name @0 :Text; - call @1 :EvaluatedCall; - input @2 :CallInput; -} - -# Main communication structs with the plugin -struct PluginCall { - union { - signature @0 :Void; - callInfo @1 :CallInfo; - collapseCustomValue @2 :PluginData; - } -} - -struct PluginResponse { - union { - error @0 :LabeledError; - signature @1 :List(Signature); - value @2 :Value; - pluginData @3 :PluginDataResponse; - } - - struct PluginDataResponse { - name @0 :Text; - data @1 :PluginData; - } -} - -struct LabeledError { - label @0 :Text; - msg @1 :Text; - # Optional Value. When decoding check if it exists (has_span) - span @2 :Span; -} diff --git a/crates/nu-plugin/src/serializers/capnp/signature.rs b/crates/nu-plugin/src/serializers/capnp/signature.rs deleted file mode 100644 index 838f4d0cab..0000000000 --- a/crates/nu-plugin/src/serializers/capnp/signature.rs +++ /dev/null @@ -1,428 +0,0 @@ -use crate::plugin_capnp::{argument, flag, signature, Category as PluginCategory, Shape}; -use nu_protocol::{Category, Flag, PositionalArg, ShellError, Signature, SyntaxShape, Type}; - -pub(crate) fn serialize_signature(signature: &Signature, mut builder: signature::Builder) { - builder.set_name(signature.name.as_str()); - builder.set_usage(signature.usage.as_str()); - builder.set_extra_usage(signature.extra_usage.as_str()); - builder.set_is_filter(signature.is_filter); - - match signature.category { - Category::Default => builder.set_category(PluginCategory::Default), - Category::Conversions => builder.set_category(PluginCategory::Conversions), - Category::Core => builder.set_category(PluginCategory::Core), - Category::Date => builder.set_category(PluginCategory::Date), - Category::Env => builder.set_category(PluginCategory::Env), - Category::Experimental => builder.set_category(PluginCategory::Experimental), - Category::FileSystem => builder.set_category(PluginCategory::Filesystem), - Category::Filters => builder.set_category(PluginCategory::Filters), - Category::Formats => builder.set_category(PluginCategory::Formats), - Category::Math => builder.set_category(PluginCategory::Math), - Category::Network => builder.set_category(PluginCategory::Network), - Category::Random => builder.set_category(PluginCategory::Random), - Category::Platform => builder.set_category(PluginCategory::Platform), - Category::Shells => builder.set_category(PluginCategory::Shells), - Category::Strings => builder.set_category(PluginCategory::Strings), - Category::System => builder.set_category(PluginCategory::System), - Category::Viewers => builder.set_category(PluginCategory::Viewers), - Category::Hash => builder.set_category(PluginCategory::Hash), - Category::Generators => builder.set_category(PluginCategory::Generators), - _ => builder.set_category(PluginCategory::Default), - } - - // Serializing list of search terms - let mut search_terms_builder = builder - .reborrow() - .init_search_terms(signature.search_terms.len() as u32); - - signature - .search_terms - .iter() - .enumerate() - .for_each(|(index, term)| search_terms_builder.set(index as u32, term.as_str())); - - // Serializing list of required arguments - let mut required_list = builder - .reborrow() - .init_required_positional(signature.required_positional.len() as u32); - - for (index, arg) in signature.required_positional.iter().enumerate() { - let inner_builder = required_list.reborrow().get(index as u32); - serialize_argument(arg, inner_builder) - } - - // Serializing list of optional arguments - let mut optional_list = builder - .reborrow() - .init_optional_positional(signature.optional_positional.len() as u32); - - for (index, arg) in signature.optional_positional.iter().enumerate() { - let inner_builder = optional_list.reborrow().get(index as u32); - serialize_argument(arg, inner_builder) - } - - // Serializing rest argument - if let Some(arg) = &signature.rest_positional { - let rest_argument = builder.reborrow().init_rest(); - serialize_argument(arg, rest_argument) - } - - // Serializing the named arguments - let mut named_list = builder.reborrow().init_named(signature.named.len() as u32); - for (index, arg) in signature.named.iter().enumerate() { - let inner_builder = named_list.reborrow().get(index as u32); - serialize_flag(arg, inner_builder) - } -} - -fn serialize_argument(arg: &PositionalArg, mut builder: argument::Builder) { - builder.set_name(arg.name.as_str()); - builder.set_desc(arg.desc.as_str()); - - match arg.shape { - SyntaxShape::Boolean => builder.set_shape(Shape::Boolean), - SyntaxShape::String => builder.set_shape(Shape::String), - SyntaxShape::Int => builder.set_shape(Shape::Int), - SyntaxShape::Number => builder.set_shape(Shape::Number), - _ => builder.set_shape(Shape::Any), - } -} - -fn serialize_flag(arg: &Flag, mut builder: flag::Builder) { - builder.set_long(arg.long.as_str()); - builder.set_required(arg.required); - builder.set_desc(arg.desc.as_str()); - - if let Some(val) = arg.short { - let mut inner_builder = builder.reborrow().init_short(1); - inner_builder.push_str(format!("{}", val).as_str()); - } - - match &arg.arg { - None => builder.set_arg(Shape::None), - Some(shape) => match shape { - SyntaxShape::Boolean => builder.set_arg(Shape::Boolean), - SyntaxShape::String => builder.set_arg(Shape::String), - SyntaxShape::Int => builder.set_arg(Shape::Int), - SyntaxShape::Number => builder.set_arg(Shape::Number), - _ => builder.set_arg(Shape::Any), - }, - } -} - -pub(crate) fn deserialize_signature(reader: signature::Reader) -> Result { - let name = reader - .get_name() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - let usage = reader - .get_usage() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - let extra_usage = reader - .get_extra_usage() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - let is_filter = reader.get_is_filter(); - - let category = match reader - .get_category() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))? - { - PluginCategory::Default => Category::Default, - PluginCategory::Conversions => Category::Conversions, - PluginCategory::Core => Category::Core, - PluginCategory::Date => Category::Date, - PluginCategory::Env => Category::Env, - PluginCategory::Experimental => Category::Experimental, - PluginCategory::Filesystem => Category::FileSystem, - PluginCategory::Filters => Category::Filters, - PluginCategory::Formats => Category::Formats, - PluginCategory::Math => Category::Math, - PluginCategory::Strings => Category::Strings, - PluginCategory::System => Category::System, - PluginCategory::Viewers => Category::Viewers, - PluginCategory::Network => Category::Network, - PluginCategory::Random => Category::Random, - PluginCategory::Platform => Category::Platform, - PluginCategory::Shells => Category::Shells, - PluginCategory::Hash => Category::Hash, - PluginCategory::Generators => Category::Generators, - }; - - // Deserializing list of search terms - let search_terms = reader - .get_search_terms() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))? - .iter() - .map(|term| { - term.map_err(|e| ShellError::PluginFailedToDecode(e.to_string())) - .map(|term| term.to_string()) - }) - .collect::, ShellError>>()?; - - // Deserializing required arguments - let required_list = reader - .get_required_positional() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let required_positional = required_list - .iter() - .map(deserialize_argument) - .collect::, ShellError>>()?; - - // Deserializing optional arguments - let optional_list = reader - .get_optional_positional() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let optional_positional = optional_list - .iter() - .map(deserialize_argument) - .collect::, ShellError>>()?; - - // Deserializing rest arguments - let rest_positional = if reader.has_rest() { - let argument_reader = reader - .get_rest() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - Some(deserialize_argument(argument_reader)?) - } else { - None - }; - - // Deserializing named arguments - let named_list = reader - .get_named() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let named = named_list - .iter() - .map(deserialize_flag) - .collect::, ShellError>>()?; - - // FIXME: add input/output type to deserialize - - Ok(Signature { - name: name.to_string(), - usage: usage.to_string(), - extra_usage: extra_usage.to_string(), - search_terms, - required_positional, - optional_positional, - rest_positional, - input_type: Type::Any, - output_type: Type::Any, - named, - is_filter, - creates_scope: false, - category, - }) -} - -fn deserialize_argument(reader: argument::Reader) -> Result { - let name = reader - .get_name() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let desc = reader - .get_desc() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let shape = reader - .get_shape() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let shape = match shape { - Shape::String => SyntaxShape::String, - Shape::Int => SyntaxShape::Int, - Shape::Number => SyntaxShape::Number, - Shape::Boolean => SyntaxShape::Boolean, - Shape::Any => SyntaxShape::Any, - Shape::None => SyntaxShape::Any, - }; - - Ok(PositionalArg { - name: name.to_string(), - desc: desc.to_string(), - shape, - var_id: None, - default_value: None, - }) -} - -fn deserialize_flag(reader: flag::Reader) -> Result { - let long = reader - .get_long() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let desc = reader - .get_desc() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let required = reader.get_required(); - - let short = if reader.has_short() { - let short_reader = reader - .get_short() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - short_reader.chars().next() - } else { - None - }; - - let arg = reader - .get_arg() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let arg = match arg { - Shape::None => None, - Shape::Any => Some(SyntaxShape::Any), - Shape::String => Some(SyntaxShape::String), - Shape::Int => Some(SyntaxShape::Int), - Shape::Number => Some(SyntaxShape::Number), - Shape::Boolean => Some(SyntaxShape::Boolean), - }; - - Ok(Flag { - long: long.to_string(), - short, - arg, - required, - desc: desc.to_string(), - var_id: None, - default_value: None, - }) -} - -#[cfg(test)] -mod tests { - use super::*; - use capnp::serialize; - use nu_protocol::{Category, Signature, SyntaxShape}; - - pub fn write_buffer( - signature: &Signature, - writer: &mut impl std::io::Write, - ) -> Result<(), ShellError> { - let mut message = ::capnp::message::Builder::new_default(); - - let builder = message.init_root::(); - - serialize_signature(signature, builder); - - serialize::write_message(writer, &message) - .map_err(|e| ShellError::PluginFailedToEncode(e.to_string())) - } - - pub fn read_buffer(reader: &mut impl std::io::BufRead) -> Result { - let message_reader = - serialize::read_message(reader, ::capnp::message::ReaderOptions::new()).unwrap(); - - let reader = message_reader - .get_root::() - .map_err(|e| ShellError::PluginFailedToEncode(e.to_string()))?; - - deserialize_signature(reader) - } - - #[test] - fn value_round_trip() { - let signature = Signature::build("nu-plugin") - .required("first", SyntaxShape::String, "first required") - .required("second", SyntaxShape::Int, "second required") - .required_named("first-named", SyntaxShape::String, "first named", Some('f')) - .required_named("second-named", SyntaxShape::Int, "first named", Some('s')) - .required_named("name", SyntaxShape::String, "first named", Some('n')) - .required_named("string", SyntaxShape::String, "second named", Some('x')) - .switch("switch", "some switch", None) - .rest("remaining", SyntaxShape::Int, "remaining") - .category(Category::Conversions); - - let mut buffer: Vec = Vec::new(); - write_buffer(&signature, &mut buffer).expect("unable to serialize message"); - let returned_signature = - read_buffer(&mut buffer.as_slice()).expect("unable to deserialize message"); - - assert_eq!(signature.name, returned_signature.name); - assert_eq!(signature.usage, returned_signature.usage); - assert_eq!(signature.extra_usage, returned_signature.extra_usage); - assert_eq!(signature.is_filter, returned_signature.is_filter); - assert_eq!(signature.category, returned_signature.category); - - signature - .required_positional - .iter() - .zip(returned_signature.required_positional.iter()) - .for_each(|(lhs, rhs)| assert_eq!(lhs, rhs)); - - signature - .optional_positional - .iter() - .zip(returned_signature.optional_positional.iter()) - .for_each(|(lhs, rhs)| assert_eq!(lhs, rhs)); - - signature - .named - .iter() - .zip(returned_signature.named.iter()) - .for_each(|(lhs, rhs)| assert_eq!(lhs, rhs)); - - assert_eq!( - signature.rest_positional, - returned_signature.rest_positional, - ); - } - - #[test] - fn value_round_trip_2() { - let signature = Signature::build("test-1") - .usage("Signature test 1 for plugin. Returns Value::Nothing") - .search_terms(vec!["a".into(), "b".into()]) - .required("a", SyntaxShape::Int, "required integer value") - .required("b", SyntaxShape::String, "required string value") - .optional("opt", SyntaxShape::Boolean, "Optional boolean") - .switch("flag", "a flag for the signature", Some('f')) - .named("named", SyntaxShape::String, "named string", Some('n')) - .category(Category::Experimental); - - let mut buffer: Vec = Vec::new(); - write_buffer(&signature, &mut buffer).expect("unable to serialize message"); - let returned_signature = - read_buffer(&mut buffer.as_slice()).expect("unable to deserialize message"); - - assert_eq!(signature.name, returned_signature.name); - assert_eq!(signature.usage, returned_signature.usage); - assert_eq!(signature.extra_usage, returned_signature.extra_usage); - assert_eq!(signature.is_filter, returned_signature.is_filter); - assert_eq!(signature.category, returned_signature.category); - - signature - .search_terms - .iter() - .zip(returned_signature.search_terms.iter()) - .for_each(|(lhs, rhs)| assert_eq!(lhs, rhs)); - - signature - .required_positional - .iter() - .zip(returned_signature.required_positional.iter()) - .for_each(|(lhs, rhs)| assert_eq!(lhs, rhs)); - - signature - .optional_positional - .iter() - .zip(returned_signature.optional_positional.iter()) - .for_each(|(lhs, rhs)| assert_eq!(lhs, rhs)); - - signature - .named - .iter() - .zip(returned_signature.named.iter()) - .for_each(|(lhs, rhs)| assert_eq!(lhs, rhs)); - - assert_eq!( - signature.rest_positional, - returned_signature.rest_positional, - ); - } -} diff --git a/crates/nu-plugin/src/serializers/capnp/value.rs b/crates/nu-plugin/src/serializers/capnp/value.rs deleted file mode 100644 index 1cef8a8766..0000000000 --- a/crates/nu-plugin/src/serializers/capnp/value.rs +++ /dev/null @@ -1,375 +0,0 @@ -use crate::plugin_capnp::value; -use nu_protocol::{ShellError, 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::Record { cols, vals, span } => { - let mut record_builder = builder.reborrow().init_record(); - - let mut cols_builder = record_builder.reborrow().init_cols(cols.len() as u32); - cols.iter() - .enumerate() - .for_each(|(index, col)| cols_builder.set(index as u32, col.as_str())); - - let mut values_builder = record_builder.reborrow().init_vals(vals.len() as u32); - vals.iter().enumerate().for_each(|(index, value)| { - let inner_builder = values_builder.reborrow().get(index as u32); - serialize_value(value, inner_builder); - }); - - *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 - - // FIXME: put this in a proper span - Span { start: 0, end: 0 } - } - }; - - 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, head: Span) -> Result { - let span_reader = reader - .get_span() - .map_err(|e| ShellError::PluginFailedToDecode(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| ShellError::PluginFailedToDecode(e.to_string()))? - .to_string(); - Ok(Value::String { val: string, span }) - } - Ok(value::Record(record)) => { - let record = record.map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let cols = record - .get_cols() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))? - .iter() - .map(|col| { - col.map_err(|e| ShellError::PluginFailedToDecode(e.to_string())) - .map(|col| col.to_string()) - }) - .collect::, ShellError>>()?; - - let vals = record - .get_vals() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))? - .iter() - .map(move |x| deserialize_value(x, span)) - .collect::, ShellError>>()?; - - Ok(Value::Record { cols, vals, span }) - } - Ok(value::List(vals)) => { - let values = vals.map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let values_list = values - .iter() - .map(move |x| deserialize_value(x, span)) - .collect::, ShellError>>()?; - - Ok(Value::List { - vals: values_list, - span, - }) - } - Err(capnp::NotInSchema(_)) => Ok(Value::Nothing { span: head }), - } -} - -#[cfg(test)] -mod tests { - use super::*; - use capnp::serialize; - use nu_protocol::{Span, Value}; - - pub fn write_buffer(value: &Value, writer: &mut impl std::io::Write) -> Result<(), ShellError> { - let mut message = ::capnp::message::Builder::new_default(); - - let mut builder = message.init_root::(); - - serialize_value(value, builder.reborrow()); - - serialize::write_message(writer, &message) - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string())) - } - - pub fn read_buffer(reader: &mut impl std::io::BufRead) -> Result { - let message_reader = - serialize::read_message(reader, ::capnp::message::ReaderOptions::new()).unwrap(); - - let reader = message_reader - .get_root::() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - let span = reader - .get_span() - .map_err(|e| ShellError::PluginFailedToDecode(e.to_string()))?; - - deserialize_value( - reader.reborrow(), - Span { - start: span.get_start() as usize, - end: span.get_end() as usize, - }, - ) - } - - #[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 = 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 = 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 = 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 = 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 record_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 vals = 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 cols = vec![ - "bool".to_string(), - "int".to_string(), - "float".to_string(), - "string".to_string(), - "list".to_string(), - ]; - - let record = Value::Record { - cols, - vals, - span: Span { start: 1, end: 20 }, - }; - - let mut buffer: Vec = Vec::new(); - write_buffer(&record, &mut buffer).expect("unable to serialize message"); - let returned_record = - read_buffer(&mut buffer.as_slice()).expect("unable to deserialize message"); - - assert_eq!(record, returned_record) - } -} diff --git a/crates/nu-plugin/src/serializers/mod.rs b/crates/nu-plugin/src/serializers/mod.rs index 398765df8e..5df43ab1d3 100644 --- a/crates/nu-plugin/src/serializers/mod.rs +++ b/crates/nu-plugin/src/serializers/mod.rs @@ -4,13 +4,11 @@ use crate::{ }; use nu_protocol::ShellError; -pub mod capnp; pub mod json; pub mod msgpack; #[derive(Clone, Debug)] pub enum EncodingType { - Capnp(capnp::CapnpSerializer), Json(json::JsonSerializer), MsgPack(msgpack::MsgPackSerializer), } @@ -18,7 +16,6 @@ pub enum EncodingType { impl EncodingType { pub fn try_from_bytes(bytes: &[u8]) -> Option { match bytes { - b"capnp" => Some(Self::Capnp(capnp::CapnpSerializer {})), b"json" => Some(Self::Json(json::JsonSerializer {})), b"msgpack" => Some(Self::MsgPack(msgpack::MsgPackSerializer {})), _ => None, @@ -31,7 +28,6 @@ impl EncodingType { writer: &mut impl std::io::Write, ) -> Result<(), ShellError> { match self { - EncodingType::Capnp(encoder) => encoder.encode_call(plugin_call, writer), EncodingType::Json(encoder) => encoder.encode_call(plugin_call, writer), EncodingType::MsgPack(encoder) => encoder.encode_call(plugin_call, writer), } @@ -42,7 +38,6 @@ impl EncodingType { reader: &mut impl std::io::BufRead, ) -> Result { match self { - EncodingType::Capnp(encoder) => encoder.decode_call(reader), EncodingType::Json(encoder) => encoder.decode_call(reader), EncodingType::MsgPack(encoder) => encoder.decode_call(reader), } @@ -54,7 +49,6 @@ impl EncodingType { writer: &mut impl std::io::Write, ) -> Result<(), ShellError> { match self { - EncodingType::Capnp(encoder) => encoder.encode_response(plugin_response, writer), EncodingType::Json(encoder) => encoder.encode_response(plugin_response, writer), EncodingType::MsgPack(encoder) => encoder.encode_response(plugin_response, writer), } @@ -65,7 +59,6 @@ impl EncodingType { reader: &mut impl std::io::BufRead, ) -> Result { match self { - EncodingType::Capnp(encoder) => encoder.decode_response(reader), EncodingType::Json(encoder) => encoder.decode_response(reader), EncodingType::MsgPack(encoder) => encoder.decode_response(reader), } @@ -73,7 +66,6 @@ impl EncodingType { pub fn to_str(&self) -> &'static str { match self { - Self::Capnp(_) => "capnp", Self::Json(_) => "json", Self::MsgPack(_) => "msgpack", } diff --git a/crates/nu_plugin_example/src/main.rs b/crates/nu_plugin_example/src/main.rs index 78cf247cc8..d8e7ae2076 100644 --- a/crates/nu_plugin_example/src/main.rs +++ b/crates/nu_plugin_example/src/main.rs @@ -4,7 +4,7 @@ use nu_plugin_example::Example; fn main() { // When defining your plugin, you can select the Serializer that could be // used to encode and decode the messages. The available options are - // CapnpSerializer and JsonSerializer. Both are defined in the serializer + // MsgPackSerializer and JsonSerializer. Both are defined in the serializer // folder in nu-plugin. serve_plugin(&mut Example {}, MsgPackSerializer {})