<commit_before>// Copyright 2016 <NAME>
//
// Licensed under the Apache License, Version 2.0 
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0>. 
// This file may not be copied, modified, or distributed
// except according to those terms.


#![allow(non_upper_case_globals)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]

#[macro_use] extern crate log;
extern crate serde_json;
extern crate serde;
extern crate melnorme_util as util;

pub mod json_util;
pub mod jsonrpc_objects;
pub mod service_util;
pub mod output_agent;

/* -----------------  ----------------- */

use util::core::*;

use std::collections::HashMap;
use std::result::Result;

use std::sync::Arc;
use std::sync::Mutex;

use service_util::ServiceError;
use service_util::ServiceResult;
use service_util::Provider;

use jsonrpc_objects::*;


/* -----------------  JsonRpcEndpoint  ----------------- */

use output_agent::OutputAgent;
use output_agent::OutputAgentTask;
use output_agent::AgentRunnable;


/// A JSON-RPC Server-role than can receive requests.
/// TODO: Client role (send requests)
pub struct JsonRpcEndpoint {
	pub request_handler : Box<RpcRequestHandler>,
	output_agent : Arc<Mutex<OutputAgent>>,
}

impl JsonRpcEndpoint {
	
	pub fn start<AGENT_RUNNER>(agent_runner: AGENT_RUNNER, request_handler: Box<RpcRequestHandler>) 
		-> JsonRpcEndpoint
	where 
		AGENT_RUNNER : AgentRunnable,
		AGENT_RUNNER : Send + 'static,
	{
		let output_agent = OutputAgent::start(agent_runner);
		Self::start_with_output_agent(output_agent, request_handler)
	}
	
	pub fn start_with_output_agent(output_agent: OutputAgent, request_handler: Box<RpcRequestHandler>) 
		-> JsonRpcEndpoint
	{
		JsonRpcEndpoint { request_handler: request_handler, output_agent : newArcMutex(output_agent) }
	}
	
	pub fn is_shutdown(& self) -> bool {
		self.output_agent.lock().unwrap().is_shutdown()
	}
	
	pub fn shutdown(&mut self) {
		self.output_agent.lock().unwrap().shutdown_and_join();
	}
	
	pub fn handle_message(&mut self, message: &str) {
		match parse_jsonrpc_request(message) {
			Ok(rpc_request) => { 
				self.handle_request(rpc_request);
			} 
			Err(error) => {
				// If we can't parse JsonRpcRequest, send an error response with null id
				let id = RpcId::Null;
				submit_write_task(&mut self.output_agent, JsonRpcResponse::new_error(id, error).to_message()); 
			}
		}
	}
	
	pub fn handle_request(&mut self, request: JsonRpcRequest) {
		let output_agent = self.output_agent.clone();
		
		let on_response : Box<FnMut(Option<JsonRpcResponse>)> = new(move |response: Option<JsonRpcResponse>| {
			if let Some(response) = response {
				submit_write_task(&output_agent, response.to_message()); 
			} else {
				let method_name = ""; // TODO
				info!("JSON-RPC notification complete. {:?}", method_name);
			} 
		});
		
		let completable = JsonRpcResponseCompletable::new(request.id, on_response);
		self.request_handler.handle_request(&request.method, request.params, completable); 
	}
	
}

pub fn run_message_read_loop<PROVIDER>(jsonrpc: Arc<Mutex<JsonRpcEndpoint>>, mut input: PROVIDER) 
	-> GResult<()>
where
	PROVIDER : Provider<String, GError>
{
	loop {
		let message = try!(input.obtain_next());
		
		let mut jsonrpc_lock = jsonrpc.lock().unwrap();
		jsonrpc_lock.handle_message(&message);
	}
}

/* ----------------- Response handling ----------------- */

pub trait RpcRequestHandler {
	
	fn handle_request(
		&mut self, request_method: &str, request_params: JsonRpcParams, completable: JsonRpcResponseCompletable
	);
}

pub struct JsonRpcResponseCompletable {
	completion_flag: FinishedFlag,
	id: Option<RpcId>,
	on_response: Box<FnMut(Option<JsonRpcResponse>)>,
}

impl JsonRpcResponseCompletable {
	
	pub fn new(id: Option<RpcId>, on_response: Box<FnMut(Option<JsonRpcResponse>)>) -> JsonRpcResponseCompletable {
		JsonRpcResponseCompletable { 
			completion_flag : FinishedFlag(false), id : id, on_response: on_response
		}
	}
	
	pub fn complete(mut self, rpc_result: Option<JsonRpcResult_Or_Error>) {
		self.completion_flag.finish();
		
		// From the spec: `A Notification is a Request object without an "id" member.`
		if let Some(rpc_result) = rpc_result {
			
			let response =
			if let Some(id) = self.id {
				JsonRpcResponse{ id : id, result_or_error : rpc_result }
			} else {
				JsonRpcResponse::new_error(RpcId::Null, 
					error_JSON_RPC_InvalidRequest("Property `id` not provided for request."))
			};
			
			(self.on_response)(Some(response));
		} else {
			(self.on_response)(None)
		}
	}
	
	pub fn complete_with_error(self, error: JsonRpcError) {
		self.complete(Some(JsonRpcResult_Or_Error::Error(error)));
	}
	
	pub fn sync_handle_request<PARAMS, RET, RET_ERROR, METHOD>(
		self, params: JsonRpcParams, method_fn: METHOD
	) 
	where 
		PARAMS : serde::Deserialize, 
		RET : serde::Serialize, 
		RET_ERROR : serde::Serialize ,
		METHOD : FnOnce(PARAMS) -> ServiceResult<RET, RET_ERROR>,
	{
		let method_fn = move |params| Some(method_fn(params));
		let result = invoke_method_with_fn(params, method_fn);
		self.complete(result);
	}
	
	pub fn sync_handle_notification<PARAMS, METHOD>(
		self, params: JsonRpcParams, method_fn: METHOD
	) 
	where 
		PARAMS : serde::Deserialize, 
		METHOD : FnOnce(PARAMS),
	{
		let method_fn = move |params| { method_fn(params); None };
		let result = invoke_method_with_fn::<_, (), (), _>(params, method_fn);
		self.complete(result);
	}
	
}

pub fn invoke_method_with_fn<PARAMS, RET, RET_ERROR, METHOD>(
	params: JsonRpcParams,
	method_fn: METHOD
) -> Option<JsonRpcResult_Or_Error>
	where 
	PARAMS : serde::Deserialize, 
	RET : serde::Serialize, 
	RET_ERROR : serde::Serialize,
	METHOD : FnOnce(PARAMS) -> Option<ServiceResult<RET, RET_ERROR>>
{
	let params_value = params.into_value();
	
	let params_result : Result<PARAMS, _> = serde_json::from_value(params_value);
	
	let result = 
	match params_result {
		Ok(params) => { 
			method_fn(params) 
		} 
		Err(error) => { 
			return Some(JsonRpcResult_Or_Error::Error(error_JSON_RPC_InvalidParams(error)));
		}
	};
	
	let result = 
	if let Some(result) = result {
		result
	} else {
		return None;
	};
	
	match result {
		Ok(ret) => {
			let ret = serde_json::to_value(&ret);
			return Some(JsonRpcResult_Or_Error::Result(ret)); 
		} 
		Err(error) => {
			let error : ServiceError<RET_ERROR> = error; // FIXME cleanup syntax
			let json_rpc_error = JsonRpcError { 
				code : error.code as i64, // FIXME review truncation
				message : error.message,
				data : Some(serde_json::to_value(&error.data)),
			};
			
			return Some(JsonRpcResult_Or_Error::Error(json_rpc_error));
		}
	}
}
	
	
pub fn submit_write_task(output_agent: &Arc<Mutex<OutputAgent>>, rpc_message: JsonRpcMessage) {
	
	let write_task : OutputAgentTask = Box::new(move |mut response_handler| {
		info!("JSON-RPC message: {:?}", rpc_message);
		
		let response_str = serde_json::to_string(&rpc_message).unwrap_or_else(|error| -> String { 
			panic!("Failed to serialize to JSON object: {}", error);
		});
		
		let write_res = response_handler.write_message(&response_str);
		if let Err(error) = write_res {
			// FIXME handle output stream write error by shutting down
			error!("Error writing JSON-RPC message: {}", error);
		};
	});
	
	let res = {
		output_agent.lock().unwrap().try_submit_task(write_task)
	}; 
	// If res is error, panic here, outside of thread lock
	res.expect("Output agent is shutdown or thread panicked!");
}

/* -----------------  Request sending  ----------------- */

impl JsonRpcEndpoint {
	
	// TODO
//	pub fn send_request<
//		PARAMS : serde::Serialize, 
//		RET: serde::Deserialize,
//		RET_ERROR : serde::Deserialize,
//	>(&mut self, method_name: &str, params: PARAMS) -> GResult<Future<ServiceResult<RET, RET_ERROR>>> {
//		let id = None; // FIXME
//			
//		self.do_send_request(id, method_name, params)
//	}
	
	pub fn do_send_request<
		PARAMS : serde::Serialize, 
		RET: serde::Deserialize,
		RET_ERROR : serde::Deserialize,
	>(&mut self, id: Option<RpcId>, method_name: &str, params: PARAMS) -> GResult<Future<ServiceResult<RET, RET_ERROR>>> {
		let params_value = serde_json::to_value(&params);
		let params = try!(jsonrpc_objects::parse_jsonrpc_params(params_value));
		
		let rpc_request = JsonRpcRequest { id: id, method : method_name.into(), params : params };
		
		let future = Future(None);
		submit_write_task(&self.output_agent, JsonRpcMessage::Request(rpc_request));
		
		Ok(future)
	}
	
	pub fn send_notification<
		PARAMS : serde::Serialize, 
	>(&mut self, method_name: &str, params: PARAMS) -> GResult<()> {
		let id = None;
		
		let future: Future<ServiceResult<(), ()>> = try!(self.do_send_request(id, method_name, params));
		future.complete(Ok(()));
		Ok(())
	}
	
}

// FIXME: use upcoming futures API, this is just a mock ATM
pub struct Future<T>(Option<T>); 

impl<T> Future<T> {
	pub fn is_completed(&self) -> bool {
		// TODO
		true
	}
	
	pub fn complete(&self, _result: T) {
	}
}

/* -----------------  ----------------- */

pub struct MapRpcRequestHandler {
	pub method_handlers : HashMap<String, Box<RpcMethodHandler>>,
}

impl MapRpcRequestHandler {
	
	pub fn new() -> MapRpcRequestHandler {
		 MapRpcRequestHandler { method_handlers : HashMap::new() }
	}
	
	pub fn add_notification<
		PARAMS : serde::Deserialize + 'static,
	>(
		&mut self,
		method_name: &'static str, 
		method_fn: Box<Fn(PARAMS)>
	) {
		let handler : Box<Fn(_) -> Option<ServiceResult<(), ()>>> = new(move |p| { method_fn(p); None });
		self.add_rpc_handler(method_name, handler);
	}
	
	pub fn add_request<
		PARAMS : serde::Deserialize + 'static, 
		RET : serde::Serialize + 'static, 
		RET_ERROR : serde::Serialize + 'static
	>(
		&mut self,
		method_name: &'static str, 
		method_fn: Box<Fn(PARAMS) -> ServiceResult<RET, RET_ERROR>>
	) {
		let handler : Box<Fn(_) -> Option<_>> = new(move |p| { Some(method_fn(p)) });
		self.add_rpc_handler(method_name, handler);
	}
	
	pub fn add_rpc_handler<METHOD_HANDLER: RpcMethodHandler + 'static>(
		&mut self,
		method_name: &'static str,
		method_handler: METHOD_HANDLER
	) {
		self.method_handlers.insert(method_name.to_string(), new(method_handler));
	}
	
	fn do_invoke_method(
		&mut self, 
		method_name: &str, 
		completable: JsonRpcResponseCompletable,
		request_params: JsonRpcParams,
	) {
		let rpc_result = 
		if let Some(dispatcher_fn) = self.method_handlers.get(method_name) 
		{
			// FIXME: asynchronous operation 
			dispatcher_fn.handle_invocation(request_params)
		} else {
			Some(JsonRpcResult_Or_Error::Error(error_JSON_RPC_MethodNotFound()))
		};
		completable.complete(rpc_result);
	}
	
}

impl RpcRequestHandler for MapRpcRequestHandler {
	
	fn handle_request(&mut self, request_method: &str, request_params: JsonRpcParams, 
		completable: JsonRpcResponseCompletable) 
	{
		self.do_invoke_method(request_method, completable, request_params);
	}
	
}

pub trait RpcMethodHandler {
	
	fn handle_invocation(&self, params: JsonRpcParams) -> Option<JsonRpcResult_Or_Error>;
	
}

impl<
	PARAMS : serde::Deserialize, 
	RET : serde::Serialize,
	RET_ERROR : serde::Serialize,
> RpcMethodHandler for Box<Fn(PARAMS) -> Option<ServiceResult<RET, RET_ERROR>>> {
	
	fn handle_invocation(&self, params: JsonRpcParams) -> Option<JsonRpcResult_Or_Error> {
		invoke_method_with_fn(params, self.as_ref())
	}
	
}


/* ----------------- Tests ----------------- */

mod tests_sample_types;

#[cfg(test)]<commit_msg>Cleanup RpcMethodHandler, enable async response<commit_after>// Copyright 2016 <NAME>
//
// Licensed under the Apache License, Version 2.0 
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0>. 
// This file may not be copied, modified, or distributed
// except according to those terms.


#![allow(non_upper_case_globals)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]

#[macro_use] extern crate log;
extern crate serde_json;
extern crate serde;
extern crate melnorme_util as util;

pub mod json_util;
pub mod jsonrpc_objects;
pub mod service_util;
pub mod output_agent;

/* -----------------  ----------------- */

use util::core::*;

use std::collections::HashMap;
use std::result::Result;

use std::sync::Arc;
use std::sync::Mutex;

use service_util::ServiceError;
use service_util::ServiceResult;
use service_util::Provider;

use jsonrpc_objects::*;


/* -----------------  JsonRpcEndpoint  ----------------- */

use output_agent::OutputAgent;
use output_agent::OutputAgentTask;
use output_agent::AgentRunnable;


/// A JSON-RPC Server-role than can receive requests.
/// TODO: Client role (send requests)
pub struct JsonRpcEndpoint {
	pub request_handler : Box<RpcRequestHandler>,
	output_agent : Arc<Mutex<OutputAgent>>,
}

impl JsonRpcEndpoint {
	
	pub fn start<AGENT_RUNNER>(agent_runner: AGENT_RUNNER, request_handler: Box<RpcRequestHandler>) 
		-> JsonRpcEndpoint
	where 
		AGENT_RUNNER : AgentRunnable,
		AGENT_RUNNER : Send + 'static,
	{
		let output_agent = OutputAgent::start(agent_runner);
		Self::start_with_output_agent(output_agent, request_handler)
	}
	
	pub fn start_with_output_agent(output_agent: OutputAgent, request_handler: Box<RpcRequestHandler>) 
		-> JsonRpcEndpoint
	{
		JsonRpcEndpoint { request_handler: request_handler, output_agent : newArcMutex(output_agent) }
	}
	
	pub fn is_shutdown(& self) -> bool {
		self.output_agent.lock().unwrap().is_shutdown()
	}
	
	pub fn shutdown(&mut self) {
		self.output_agent.lock().unwrap().shutdown_and_join();
	}
	
	pub fn handle_message(&mut self, message: &str) {
		match parse_jsonrpc_request(message) {
			Ok(rpc_request) => { 
				self.handle_request(rpc_request);
			} 
			Err(error) => {
				// If we can't parse JsonRpcRequest, send an error response with null id
				let id = RpcId::Null;
				submit_write_task(&mut self.output_agent, JsonRpcResponse::new_error(id, error).to_message()); 
			}
		}
	}
	
	pub fn handle_request(&mut self, request: JsonRpcRequest) {
		let output_agent = self.output_agent.clone();
		
		let on_response : Box<FnMut(Option<JsonRpcResponse>)> = new(move |response: Option<JsonRpcResponse>| {
			if let Some(response) = response {
				submit_write_task(&output_agent, response.to_message()); 
			} else {
				let method_name = ""; // TODO
				info!("JSON-RPC notification complete. {:?}", method_name);
			} 
		});
		
		let completable = JsonRpcResponseCompletable::new(request.id, on_response);
		self.request_handler.handle_request(&request.method, request.params, completable); 
	}
	
}

pub fn run_message_read_loop<PROVIDER>(jsonrpc: Arc<Mutex<JsonRpcEndpoint>>, mut input: PROVIDER) 
	-> GResult<()>
where
	PROVIDER : Provider<String, GError>
{
	loop {
		let message = try!(input.obtain_next());
		
		let mut jsonrpc_lock = jsonrpc.lock().unwrap();
		jsonrpc_lock.handle_message(&message);
	}
}

/* ----------------- Response handling ----------------- */

pub trait RpcRequestHandler {
	
	fn handle_request(
		&mut self, request_method: &str, request_params: JsonRpcParams, completable: JsonRpcResponseCompletable
	);
}

pub struct JsonRpcResponseCompletable {
	completion_flag: FinishedFlag,
	id: Option<RpcId>,
	on_response: Box<FnMut(Option<JsonRpcResponse>)>,
}

impl JsonRpcResponseCompletable {
	
	pub fn new(id: Option<RpcId>, on_response: Box<FnMut(Option<JsonRpcResponse>)>) -> JsonRpcResponseCompletable {
		JsonRpcResponseCompletable { 
			completion_flag : FinishedFlag(false), id : id, on_response: on_response
		}
	}
	
	pub fn complete(mut self, rpc_result: Option<JsonRpcResult_Or_Error>) {
		self.completion_flag.finish();
		
		// From the spec: `A Notification is a Request object without an "id" member.`
		if let Some(rpc_result) = rpc_result {
			
			let response =
			if let Some(id) = self.id {
				JsonRpcResponse{ id : id, result_or_error : rpc_result }
			} else {
				JsonRpcResponse::new_error(RpcId::Null, 
					error_JSON_RPC_InvalidRequest("Property `id` not provided for request."))
			};
			
			(self.on_response)(Some(response));
		} else {
			(self.on_response)(None)
		}
	}
	
	pub fn complete_with_error(self, error: JsonRpcError) {
		self.complete(Some(JsonRpcResult_Or_Error::Error(error)));
	}
	
	pub fn sync_handle_request<PARAMS, RET, RET_ERROR, METHOD>(
		self, params: JsonRpcParams, method_fn: METHOD
	) 
	where 
		PARAMS : serde::Deserialize, 
		RET : serde::Serialize, 
		RET_ERROR : serde::Serialize ,
		METHOD : FnOnce(PARAMS) -> ServiceResult<RET, RET_ERROR>,
	{
		let method_fn = move |params| Some(method_fn(params));
		let result = invoke_method_with_fn(params, method_fn);
		self.complete(result);
	}
	
	pub fn sync_handle_notification<PARAMS, METHOD>(
		self, params: JsonRpcParams, method_fn: METHOD
	) 
	where 
		PARAMS : serde::Deserialize, 
		METHOD : FnOnce(PARAMS),
	{
		let method_fn = move |params| { method_fn(params); None };
		let result = invoke_method_with_fn::<_, (), (), _>(params, method_fn);
		self.complete(result);
	}
	
}

pub fn invoke_method_with_fn<PARAMS, RET, RET_ERROR, METHOD>(
	params: JsonRpcParams,
	method_fn: METHOD
) -> Option<JsonRpcResult_Or_Error>
	where 
	PARAMS : serde::Deserialize, 
	RET : serde::Serialize, 
	RET_ERROR : serde::Serialize,
	METHOD : FnOnce(PARAMS) -> Option<ServiceResult<RET, RET_ERROR>>
{
	let params_value = params.into_value();
	
	let params_result : Result<PARAMS, _> = serde_json::from_value(params_value);
	
	let result = 
	match params_result {
		Ok(params) => { 
			method_fn(params) 
		} 
		Err(error) => { 
			return Some(JsonRpcResult_Or_Error::Error(error_JSON_RPC_InvalidParams(error)));
		}
	};
	
	let result = 
	if let Some(result) = result {
		result
	} else {
		return None;
	};
	
	match result {
		Ok(ret) => {
			let ret = serde_json::to_value(&ret);
			return Some(JsonRpcResult_Or_Error::Result(ret)); 
		} 
		Err(error) => {
			let error : ServiceError<RET_ERROR> = error; // FIXME cleanup syntax
			let json_rpc_error = JsonRpcError { 
				code : error.code as i64, // FIXME review truncation
				message : error.message,
				data : Some(serde_json::to_value(&error.data)),
			};
			
			return Some(JsonRpcResult_Or_Error::Error(json_rpc_error));
		}
	}
}
	
	
pub fn submit_write_task(output_agent: &Arc<Mutex<OutputAgent>>, rpc_message: JsonRpcMessage) {
	
	let write_task : OutputAgentTask = Box::new(move |mut response_handler| {
		info!("JSON-RPC message: {:?}", rpc_message);
		
		let response_str = serde_json::to_string(&rpc_message).unwrap_or_else(|error| -> String { 
			panic!("Failed to serialize to JSON object: {}", error);
		});
		
		let write_res = response_handler.write_message(&response_str);
		if let Err(error) = write_res {
			// FIXME handle output stream write error by shutting down
			error!("Error writing JSON-RPC message: {}", error);
		};
	});
	
	let res = {
		output_agent.lock().unwrap().try_submit_task(write_task)
	}; 
	// If res is error, panic here, outside of thread lock
	res.expect("Output agent is shutdown or thread panicked!");
}

/* -----------------  Request sending  ----------------- */

impl JsonRpcEndpoint {
	
	// TODO
//	pub fn send_request<
//		PARAMS : serde::Serialize, 
//		RET: serde::Deserialize,
//		RET_ERROR : serde::Deserialize,
//	>(&mut self, method_name: &str, params: PARAMS) -> GResult<Future<ServiceResult<RET, RET_ERROR>>> {
//		let id = None; // FIXME
//			
//		self.do_send_request(id, method_name, params)
//	}
	
	pub fn do_send_request<
		PARAMS : serde::Serialize, 
		RET: serde::Deserialize,
		RET_ERROR : serde::Deserialize,
	>(&mut self, id: Option<RpcId>, method_name: &str, params: PARAMS) -> GResult<Future<ServiceResult<RET, RET_ERROR>>> {
		let params_value = serde_json::to_value(&params);
		let params = try!(jsonrpc_objects::parse_jsonrpc_params(params_value));
		
		let rpc_request = JsonRpcRequest { id: id, method : method_name.into(), params : params };
		
		let future = Future(None);
		submit_write_task(&self.output_agent, JsonRpcMessage::Request(rpc_request));
		
		Ok(future)
	}
	
	pub fn send_notification<
		PARAMS : serde::Serialize, 
	>(&mut self, method_name: &str, params: PARAMS) -> GResult<()> {
		let id = None;
		
		let future: Future<ServiceResult<(), ()>> = try!(self.do_send_request(id, method_name, params));
		future.complete(Ok(()));
		Ok(())
	}
	
}

// FIXME: use upcoming futures API, this is just a mock ATM
pub struct Future<T>(Option<T>); 

impl<T> Future<T> {
	pub fn is_completed(&self) -> bool {
		// TODO
		true
	}
	
	pub fn complete(&self, _result: T) {
	}
}

/* -----------------  MapRpcRequestHandler  ----------------- */

pub type RpcMethodHandler = Fn(JsonRpcParams, JsonRpcResponseCompletable);

pub struct MapRpcRequestHandler {
	pub method_handlers : HashMap<String, Box<RpcMethodHandler>>,
}

impl MapRpcRequestHandler {
	
	pub fn new() -> MapRpcRequestHandler {
		 MapRpcRequestHandler { method_handlers : HashMap::new() }
	}
	
	pub fn add_notification<
		PARAMS : serde::Deserialize + 'static,
	>(
		&mut self,
		method_name: &'static str, 
		method_fn: Box<Fn(PARAMS)>
	) {
		let req_handler : Box<RpcMethodHandler> = new(move |params, completable| {
			completable.sync_handle_notification(params, &*method_fn);
		});
		self.add_rpc_handler(method_name, req_handler);
	}
	
	pub fn add_request<
		PARAMS : serde::Deserialize + 'static, 
		RET : serde::Serialize + 'static, 
		RET_ERROR : serde::Serialize + 'static
	>(
		&mut self,
		method_name: &'static str, 
		method_fn: Box<Fn(PARAMS) -> ServiceResult<RET, RET_ERROR>>
	) {
		let req_handler : Box<RpcMethodHandler> = new(move |params, completable| {
			completable.sync_handle_request(params, &*method_fn);
		});
		self.add_rpc_handler(method_name, req_handler);
	}
	
	pub fn add_rpc_handler(
		&mut self,
		method_name: &'static str,
		method_handler: Box<RpcMethodHandler>
	) {
		self.method_handlers.insert(method_name.to_string(), method_handler);
	}
	
	fn do_invoke_method(
		&mut self, 
		method_name: &str, 
		completable: JsonRpcResponseCompletable,
		request_params: JsonRpcParams,
	) {
		if let Some(method_fn) = self.method_handlers.get(method_name) 
		{
			let method_fn : &Box<RpcMethodHandler> = method_fn;
			method_fn(request_params, completable);
		} else {
			completable.complete_with_error(error_JSON_RPC_MethodNotFound());
		};
	}
	
}

impl RpcRequestHandler for MapRpcRequestHandler {
	
	fn handle_request(&mut self, request_method: &str, request_params: JsonRpcParams, 
		completable: JsonRpcResponseCompletable) 
	{
		self.do_invoke_method(request_method, completable, request_params);
	}
	
}



/* ----------------- Tests ----------------- */

mod tests_sample_types;

#[cfg(test)]
{'fraction_non_alphanumeric': 0.14543183440399715, 'fraction_numerical': 0.0008922198429693076, 'mean_word_length': 4.192726430391476, 'pattern_counts': {'":': 0, '<': 137, '<?xml version=': 0, '>': 184, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5515276', 'n_tokens_mistral': 8356, 'n_tokens_neox': 7625, 'n_words': 1584}