Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 26 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,21 @@ bench = false

[dependencies]
rmp = "0.8.9"
rmpv = "0.4.3"
rmpv = { version = "0.4.3", features = ["with-serde"] }
log = "0.4.8"
async-trait = "0.1.22"
futures = { version = "0.3.1", features = ["io-compat"] }
tokio = { version = "1.1.1", features = ["full"] , optional = true}
tokio = { version = "1.1.1", features = ["full"] , optional = true }
tokio-util = { version = "0.6.3", features = ["compat"], optional = true }
async-std = { version = "1.4.0", features = ["attributes"], optional = true }
neovim-lib = { version = "0.6.1", optional = true }
serde = { version = "1.0.123", features = ["derive"] }
rmp-serde = "0.15.4"

[dev-dependencies]
tempdir = "0.3"
criterion = "0.3.0"
tokio = { version = "1.1.1", features = ["full"] }

[profile.bench]
lto = true
Expand Down
29 changes: 29 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ impl Display for InvalidMessage {
pub enum DecodeError {
/// Reading from the internal buffer failed.
BufferError(RmpvDecodeError),
SerdeBufferError(rmp_serde::decode::Error),
/// Reading from the stream failed. This is probably unrecoverable from, but
/// might also mean that neovim closed the stream and wants the plugin to
/// finish. See examples/quitting.rs on how this might be caught.
Expand All @@ -126,6 +127,7 @@ impl Error for DecodeError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match *self {
DecodeError::BufferError(ref e) => Some(e),
DecodeError::SerdeBufferError(ref e) => Some(e),
DecodeError::InvalidMessage(ref e) => Some(e),
DecodeError::ReaderError(ref e) => Some(e),
}
Expand All @@ -136,6 +138,9 @@ impl Display for DecodeError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let s = match *self {
DecodeError::BufferError(_) => "Error while reading from buffer",
DecodeError::SerdeBufferError(_) => {
"Error reading from buffer using serde"
}
DecodeError::InvalidMessage(_) => "Error while decoding",
DecodeError::ReaderError(_) => "Error while reading from Reader",
};
Expand All @@ -150,6 +155,12 @@ impl From<RmpvDecodeError> for Box<DecodeError> {
}
}

impl From<rmp_serde::decode::Error> for Box<DecodeError> {
fn from(err: rmp_serde::decode::Error) -> Box<DecodeError> {
Box::new(DecodeError::SerdeBufferError(err))
}
}

impl From<InvalidMessage> for Box<DecodeError> {
fn from(err: InvalidMessage) -> Box<DecodeError> {
Box::new(DecodeError::InvalidMessage(err))
Expand All @@ -167,6 +178,8 @@ impl From<io::Error> for Box<DecodeError> {
pub enum EncodeError {
/// Encoding the message into the internal buffer has failed.
BufferError(RmpvEncodeError),
SerdeBufferError(rmp_serde::encode::Error),
ToValueError(rmpv::ext::Error),
/// Writing the encoded message to the stream failed.
WriterError(io::Error),
}
Expand All @@ -175,6 +188,8 @@ impl Error for EncodeError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match *self {
EncodeError::BufferError(ref e) => Some(e),
EncodeError::ToValueError(ref e) => Some(e),
EncodeError::SerdeBufferError(ref e) => Some(e),
EncodeError::WriterError(ref e) => Some(e),
}
}
Expand All @@ -184,6 +199,8 @@ impl Display for EncodeError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let s = match *self {
Self::BufferError(_) => "Error writing to buffer",
Self::SerdeBufferError(_) => "Error writing to buffer using serde",
Self::ToValueError(_) => "Error converting serializable to Value",
Self::WriterError(_) => "Error writing to the Writer",
};

Expand All @@ -197,6 +214,18 @@ impl From<RmpvEncodeError> for Box<EncodeError> {
}
}

impl From<rmpv::ext::Error> for Box<EncodeError> {
fn from(err: rmpv::ext::Error) -> Box<EncodeError> {
Box::new(EncodeError::ToValueError(err))
}
}

impl From<rmp_serde::encode::Error> for Box<EncodeError> {
fn from(err: rmp_serde::encode::Error) -> Self {
Box::new(EncodeError::SerdeBufferError(err))
}
}

impl From<io::Error> for Box<EncodeError> {
fn from(err: io::Error) -> Box<EncodeError> {
Box::new(EncodeError::WriterError(err))
Expand Down
35 changes: 28 additions & 7 deletions src/neovim.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! An active neovim session.
use std::{
fmt,
future::Future,
sync::{
atomic::{AtomicU64, Ordering},
Expand All @@ -23,13 +24,19 @@ use crate::{
},
uioptions::UiAttachOptions,
};
use rmpv::Value;
use rmpv::{ext::to_value, Value};
use serde::{self, Deserialize, Deserializer, Serialize};

/// Pack the given arguments into a `Vec<Value>`, suitable for using it for a
/// [`call`](crate::neovim::Neovim::call) to neovim.
#[macro_export]
macro_rules! call_args {
() => (Vec::new());
() => {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's this one for? If we need an empty Vec<Value> I think type inference should usually figure that out when just using vec![], right?

{
let vec: Vec<$crate::Value> = Vec::new();
vec
}
};
($($e:expr), +,) => (call_args![$($e),*]);
($($e:expr), +) => {{
let mut vec = Vec::new();
Expand Down Expand Up @@ -96,17 +103,31 @@ where
(req, fut)
}

async fn send_msg(
/// Will panic if args is serialized into something that is not an array
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does that happen? How can the caller ensure this doesn't happen? Could we statically guarantee that somehow?

async fn send_msg<T: Serialize + fmt::Debug>(
&self,
method: &str,
args: Vec<Value>,
args: T,
) -> Result<oneshot::Receiver<ResponseResult>, Box<EncodeError>> {
let msgid = self.msgid_counter.fetch_add(1, Ordering::SeqCst);

fn get_args<T: Serialize + fmt::Debug>(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this inlined for a specific reason? I'd prefer if it weren't, unless I'm missing something.

args: T,
) -> Result<Vec<Value>, Box<EncodeError>> {
debug!("Args value is {:?}", args);
let args_value = to_value(args)?;
debug!("Args value is {:?}", args_value);

Ok(match args_value {
Value::Array(arr) => arr,
v => vec![v],
})
}

let req = RpcMessage::RpcRequest {
msgid,
method: method.to_owned(),
params: args,
params: get_args(args)?,
};

let (sender, receiver) = oneshot::channel();
Expand All @@ -119,10 +140,10 @@ where
Ok(receiver)
}

pub async fn call(
pub async fn call<T: Serialize + fmt::Debug>(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you using fmt::Debug instead of simply Debug here?

&self,
method: &str,
args: Vec<Value>,
args: T,
) -> Result<Result<Value, Value>, Box<CallError>> {
let receiver = self
.send_msg(method, args)
Expand Down
13 changes: 10 additions & 3 deletions src/neovim_api.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
//! The auto generated API for [`neovim`](crate::neovim::Neovim)
//!
//! Auto generated 2020-08-18 09:13:24.551223
use std::fmt;

use futures::io::AsyncWrite;
use serde::Serialize;

use crate::{
error::CallError,
Expand Down Expand Up @@ -1009,13 +1012,17 @@ where
.map_err(|v| Box::new(CallError::WrongValueType(v)))
}

pub async fn call_function(
pub async fn call_function<T: Serialize + fmt::Debug>(
&self,
fname: &str,
args: Vec<Value>,
args: T,
) -> Result<Value, Box<CallError>> {

#[derive(Debug, Serialize)]
struct Args<'a, T: Serialize>(&'a str, T);

self
.call("nvim_call_function", call_args![fname, args])
.call("nvim_call_function", Args(fname, args))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any blanket impl's we could take advantage of here? Maybe we can just use (fname, args)? Otoh, this might just be clearer to read.

.await??
.try_unpack()
.map_err(|v| Box::new(CallError::WrongValueType(v)))
Expand Down
Loading