From d79d42e10a75c2c4bd82cffdda229da65712b1a1 Mon Sep 17 00:00:00 2001 From: Tad Hardesty Date: Tue, 2 Apr 2019 18:29:14 -0700 Subject: [PATCH] Further restructure langserver::io for WebAssembly --- src/langserver/io/mod.rs | 15 +++++++ src/langserver/{io.rs => io/stdio.rs} | 63 ++++++--------------------- src/langserver/io/wasm.rs | 42 ++++++++++++++++++ src/langserver/main.rs | 18 +------- 4 files changed, 73 insertions(+), 65 deletions(-) create mode 100644 src/langserver/io/mod.rs rename src/langserver/{io.rs => io/stdio.rs} (54%) create mode 100644 src/langserver/io/wasm.rs diff --git a/src/langserver/io/mod.rs b/src/langserver/io/mod.rs new file mode 100644 index 00000000..bd4dc590 --- /dev/null +++ b/src/langserver/io/mod.rs @@ -0,0 +1,15 @@ +//! Pluggable backends for input/output handling. + +pub trait RequestRead { + fn read(&self) -> Option; +} + +pub trait ResponseWrite { + fn write(&self, output: String); +} + +#[cfg_attr(target_arch="wasm32", path="wasm.rs")] +#[cfg_attr(not(target_arch="wasm32"), path="stdio.rs")] +mod system; + +pub use self::system::*; diff --git a/src/langserver/io.rs b/src/langserver/io/stdio.rs similarity index 54% rename from src/langserver/io.rs rename to src/langserver/io/stdio.rs index ccb40f38..affb5ced 100644 --- a/src/langserver/io.rs +++ b/src/langserver/io/stdio.rs @@ -1,16 +1,22 @@ -// Based loosely on RLS's input/output code +//! I/O backend for standard targets. +//! +//! JSON-RPC over stdin/stdout with Content-Length headers. +use Engine; +use io::{RequestRead, ResponseWrite}; use std::io::{self, Read, Write}; -pub trait RequestRead { - fn read(&self) -> Option; +pub fn io_main() { + let stdio = StdIo; + let context = Default::default(); + let mut engine = Engine::new(&stdio, &context); + loop { + let message = stdio.read().expect("request bad read"); + engine.handle_input(&message); + } } -pub trait ResponseWrite { - fn write(&self, output: String); -} - -pub struct StdIo; +struct StdIo; impl RequestRead for StdIo { fn read(&self) -> Option { @@ -62,44 +68,3 @@ impl ResponseWrite for StdIo { stdout_lock.flush().unwrap(); } } - -#[cfg(target_arch="wasm32")] -#[allow(unsafe_code)] -pub mod wasm { - use Engine; - use super::ResponseWrite; - - extern { - fn handle_output(ptr: *const u8, len: usize); - } - - struct WasmIo; - - impl ResponseWrite for WasmIo { - fn write(&self, output: String) { - unsafe { - handle_output(output.as_ptr(), output.len()); - } - } - } - - static mut ENGINE_PTR: *mut Engine = 0 as *mut Engine; - - pub fn main() { - let wasmio = Box::leak(Box::new(WasmIo)); - let context = Box::leak(Box::new(Default::default())); - let engine = Box::new(Engine::new(wasmio, context)); - unsafe { - ENGINE_PTR = Box::into_raw(engine); - } - } - - #[no_mangle] - pub unsafe extern fn handle_input(ptr: *const u8, len: usize) { - assert!(!ENGINE_PTR.is_null()); - let engine = &mut *ENGINE_PTR; - let slice = std::slice::from_raw_parts(ptr, len); - let text = std::str::from_utf8(slice).expect("input is not utf-8"); - engine.handle_input(text); - } -} diff --git a/src/langserver/io/wasm.rs b/src/langserver/io/wasm.rs new file mode 100644 index 00000000..ea0f631b --- /dev/null +++ b/src/langserver/io/wasm.rs @@ -0,0 +1,42 @@ +//! I/O backend for WebAssembly target. +//! +//! `main()` creates an engine that will respond to calls to `handle_input()`, +//! which will then call `handle_output()` with output messages. +#![allow(unsafe_code)] + +use Engine; +use super::ResponseWrite; + +pub fn io_main() { + let wasmio = Box::leak(Box::new(WasmIo)); + let context = Box::leak(Box::new(Default::default())); + let engine = Box::new(Engine::new(wasmio, context)); + unsafe { + ENGINE_PTR = Box::into_raw(engine); + } +} + +static mut ENGINE_PTR: *mut Engine = 0 as *mut Engine; + +#[no_mangle] +pub unsafe extern fn handle_input(ptr: *const u8, len: usize) { + assert!(!ENGINE_PTR.is_null()); + let engine = &mut *ENGINE_PTR; + let slice = std::slice::from_raw_parts(ptr, len); + let text = std::str::from_utf8(slice).expect("input is not utf-8"); + engine.handle_input(text); +} + +struct WasmIo; + +impl ResponseWrite for WasmIo { + fn write(&self, output: String) { + unsafe { + handle_output(output.as_ptr(), output.len()); + } + } +} + +extern { + fn handle_output(ptr: *const u8, len: usize); +} diff --git a/src/langserver/main.rs b/src/langserver/main.rs index e17b0ec5..a924b880 100644 --- a/src/langserver/main.rs +++ b/src/langserver/main.rs @@ -6,6 +6,7 @@ //! * https://microsoft.github.io/language-server-protocol/specification //! * https://github.com/rust-lang-nursery/rls #![deny(unsafe_code)] +#![cfg_attr(not(target_arch="wasm32"), forbid(unsafe_code))] extern crate url; extern crate serde; @@ -60,22 +61,7 @@ fn main() { Err(e) => eprintln!("dir check failure: {}", e), } - #[cfg(not(target_arch="wasm32"))] - { - let stdio = io::StdIo; - let context = Default::default(); - let mut engine = Engine::new(&stdio, &context); - loop { - use io::RequestRead; - let message = stdio.read().expect("request bad read"); - engine.handle_input(&message); - } - } - - #[cfg(target_arch="wasm32")] - { - io::wasm::main(); - } + io::io_main(); } const VERSION: Option = Some(jsonrpc::Version::V2);