navy-nvim-rs 0.0.27

A library for writing neovim rpc clients
use std::io;

use rmpv::ValueRef;

use crate::rpc::payload::{NotificationPayload, RequestPayload};

pub type ResponseValue<'a> = Result<ValueRef<'a>, ValueRef<'a>>;

pub trait Handler: Send + Sync + 'static {
    fn handle_notify(&self, _payload: NotificationPayload) -> io::Result<()>;

    // Note: Delegating response encoding to the request handler by passing `Mutex<Encoder<W>>`
    // instance to this method would be more efficient. However there is currently no use case
    // that requires a request handler to return a response value. Therefore we prioritize API
    // simplicity and make the handler return the response value instead.
    fn handle_request(&self, _payload: RequestPayload) -> io::Result<ResponseValue<'_>>;
}

#[derive(Clone)]
pub struct Dummy;

impl Handler for Dummy {
    fn handle_notify(&self, _payload: NotificationPayload) -> io::Result<()> {
        Ok(())
    }

    fn handle_request(&self, _payload: RequestPayload) -> io::Result<ResponseValue<'_>> {
        Ok(Err(ValueRef::from("Not implemented")))
    }
}

#[cfg(test)]
mod tests {
    use bytes::BytesMut;
    use rmpv::{ValueRef, encode::write_value_ref};

    use super::*;
    use crate::rpc::payload::Payload;

    fn decode_payload(value: ValueRef<'_>) -> Payload {
        let mut bytes = Vec::new();
        write_value_ref(&mut bytes, &value).unwrap();
        Payload::decode(&mut BytesMut::from(bytes.as_slice())).unwrap()
    }

    #[test]
    fn dummy_ignores_notifications() {
        let Payload::Notification(payload) = decode_payload(ValueRef::Array(vec![
            ValueRef::from(2),
            ValueRef::from("event"),
            ValueRef::Array(vec![]),
        ])) else {
            panic!("expected notification");
        };

        Dummy.handle_notify(payload).unwrap();
    }

    #[test]
    fn dummy_returns_not_implemented_for_requests() {
        let Payload::Request(payload) = decode_payload(ValueRef::Array(vec![
            ValueRef::from(0),
            ValueRef::from(1),
            ValueRef::from("method"),
            ValueRef::Array(vec![]),
        ])) else {
            panic!("expected request");
        };

        assert_eq!(
            Dummy.handle_request(payload).unwrap(),
            Err(ValueRef::from("Not implemented"))
        );
    }
}