Skip to main content

alux_jsonrpc_direct/
table.rs

1use crate::error::RpcError;
2use core::error::Error;
3use core::fmt::{self, Debug, Display};
4use core::future::Future;
5use core::pin::Pin;
6use serde_json::Value;
7use std::collections::BTreeMap;
8use std::collections::btree_map::Entry;
9use std::sync::Arc;
10
11/// The answer one dispatched method produces.
12pub type Answer = Pin<Box<dyn Future<Output = Result<Value, RpcError>> + Send>>;
13
14/// One registered method: it decodes its parameters, applies its operation, and answers.
15pub(crate) type Method = Arc<dyn Fn(Option<Value>) -> Answer + Send + Sync>;
16
17/// Names a method that two composed programs both declared.
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct DuplicateMethod(pub &'static str);
20
21impl Display for DuplicateMethod {
22    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
23        write!(formatter, "method `{}` is declared twice", self.0)
24    }
25}
26
27impl Error for DuplicateMethod {}
28
29/// A JSON-RPC surface: every method a program declared, keyed by the name it answers to.
30#[derive(Clone, Default)]
31pub struct MethodTable {
32    methods: BTreeMap<&'static str, Method>,
33}
34
35impl MethodTable {
36    /// Returns every method name this surface answers to, in lexical order.
37    pub fn names(&self) -> Vec<&'static str> {
38        self.methods.keys().copied().collect()
39    }
40
41    /// Returns how many methods this surface answers to.
42    pub fn len(&self) -> usize {
43        self.methods.len()
44    }
45
46    /// Returns whether this surface answers to nothing.
47    pub fn is_empty(&self) -> bool {
48        self.methods.is_empty()
49    }
50
51    /// Composes two surfaces, which is only defined when they name different methods.
52    ///
53    /// # Errors
54    ///
55    /// Answers with the duplicated name when both surfaces declare it.
56    pub fn merge(mut self, other: Self) -> Result<Self, DuplicateMethod> {
57        for (name, method) in other.methods {
58            self.insert(name, method)?;
59        }
60
61        Ok(self)
62    }
63
64    pub(crate) fn insert(&mut self, name: &'static str, method: Method) -> Result<(), DuplicateMethod> {
65        match self.methods.entry(name) {
66            Entry::Occupied(_) => Err(DuplicateMethod(name)),
67            Entry::Vacant(entry) => {
68                entry.insert(method);
69                Ok(())
70            }
71        }
72    }
73
74    pub(crate) fn get(&self, name: &str) -> Option<&Method> {
75        self.methods.get(name)
76    }
77}
78
79impl Debug for MethodTable {
80    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
81        formatter.debug_struct("MethodTable").field("methods", &self.names()).finish()
82    }
83}