1
//! Support for decoding and encoding RPC messages.
2
//!
3
//! Every message is either a Request (sent to Arti)
4
//! or a Response (received from Arti).
5

            
6
pub(crate) mod request;
7
pub(crate) mod response;
8

            
9
use std::ffi::NulError;
10

            
11
use serde::{Deserialize, Serialize};
12

            
13
use crate::util::Utf8CString;
14

            
15
/// An identifier for a request made to the Arti RPC system.
16
///
17
/// Every request must have an ID, chosen by the application that's sending it.
18
/// If these IDs are not distinct, the application can get confused about
19
/// which reply corresponds to which request.
20
///
21
/// The [`RpcConn`](crate::conn::RpcConn) type can generate unique IDs
22
/// for outbound requests as needed.
23
#[derive(Serialize, Deserialize, Debug, Clone, Hash, Eq, PartialEq, derive_more::From)]
24
#[serde(untagged)]
25
#[non_exhaustive]
26
pub enum AnyRequestId {
27
    /// A numeric request ID.
28
    ///
29
    /// Note that values larger than `±2^53-1` may not work with all
30
    /// JSON implementations.
31
    Number(i64),
32
    /// A string request ID.
33
    String(String),
34
}
35

            
36
impl AnyRequestId {
37
    /// Convert this request ID into a json value.
38
    //
39
    // (This is a private function because we don't want to expose serde_json in our API.)
40
4148
    fn into_json_value(self) -> serde_json::Value {
41
4148
        match self {
42
4
            AnyRequestId::Number(n) => serde_json::Value::Number(n.into()),
43
4144
            AnyRequestId::String(s) => serde_json::Value::String(s),
44
        }
45
4148
    }
46
}
47

            
48
/// An identifier for some object visible to the Arti RPC system.
49
///
50
/// A single object may have multiple underlying identifiers.
51
/// These identifiers should always be treated as opaque
52
/// from the application's perspective.
53
#[derive(
54
8278
    Serialize, Deserialize, Debug, Clone, Hash, Eq, PartialEq, derive_more::From, derive_more::Into,
55
)]
56
#[serde(transparent)]
57
pub struct ObjectId(Utf8CString);
58

            
59
impl ObjectId {
60
    /// Return the global ID for an RPC connection.
61
    pub fn connection_id() -> Self {
62
        ObjectId(
63
            "connection"
64
                .to_string()
65
                .try_into()
66
                .expect("Surprising NULs in string"),
67
        )
68
    }
69

            
70
    /// Return this ID as a nul-terminated C string.
71
    #[cfg(feature = "ffi")]
72
    pub(crate) fn as_ptr(&self) -> *const std::ffi::c_char {
73
        self.0.as_ptr()
74
    }
75
}
76

            
77
impl TryFrom<String> for ObjectId {
78
    type Error = NulError;
79

            
80
    fn try_from(value: String) -> Result<Self, Self::Error> {
81
        Ok(Self(Utf8CString::try_from(value)?))
82
    }
83
}
84
impl AsRef<str> for ObjectId {
85
4
    fn as_ref(&self) -> &str {
86
4
        self.0.as_ref()
87
4
    }
88
}
89
impl From<ObjectId> for String {
90
    fn from(v: ObjectId) -> String {
91
        v.as_ref().into()
92
    }
93
}
94

            
95
/// Serde helper: deserializes (and discards) the contents of any json Object,
96
/// and does not accept any other type.
97
#[derive(Debug)]
98
struct JsonAnyObj {}
99
// Note: We can't just use `derive(Deserialize)` here, since that would permit empty arrays.
100
impl<'de> serde::de::Deserialize<'de> for JsonAnyObj {
101
10194
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
102
10194
    where
103
10194
        D: serde::Deserializer<'de>,
104
10194
    {
105
        /// Visitor to implement deserialize.
106
        struct Vis;
107
        impl<'de> serde::de::Visitor<'de> for Vis {
108
            type Value = JsonAnyObj;
109
6
            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
110
6
                formatter.write_str("a JSON object")
111
6
            }
112
10182
            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
113
10182
            where
114
10182
                A: serde::de::MapAccess<'de>,
115
10182
            {
116
                // We need to iterate over the map, or else we'll get an error.
117
24386
                while let Some((k, v)) = map.next_entry()? {
118
14204
                    // It's okay to allow any type here for keys;
119
14204
                    // serde_json won't deserialize a key  unless it is a string.
120
14204
                    let _: serde::de::IgnoredAny = k;
121
14204
                    let _: serde::de::IgnoredAny = v;
122
14204
                }
123
10180
                Ok(JsonAnyObj {})
124
10182
            }
125
        }
126

            
127
10194
        deserializer.deserialize_map(Vis)
128
10194
    }
129
}
130

            
131
#[cfg(test)]
132
mod test {
133
    // @@ begin test lint list maintained by maint/add_warning @@
134
    #![allow(clippy::bool_assert_comparison)]
135
    #![allow(clippy::clone_on_copy)]
136
    #![allow(clippy::dbg_macro)]
137
    #![allow(clippy::mixed_attributes_style)]
138
    #![allow(clippy::print_stderr)]
139
    #![allow(clippy::print_stdout)]
140
    #![allow(clippy::single_char_pattern)]
141
    #![allow(clippy::unwrap_used)]
142
    #![allow(clippy::unchecked_duration_subtraction)]
143
    #![allow(clippy::useless_vec)]
144
    #![allow(clippy::needless_pass_by_value)]
145
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
146

            
147
    use super::*;
148

            
149
    #[test]
150
    fn any_obj_good() {
151
        for ok in [
152
            r#"{}"#,
153
            r#"{"7": 7}"#,
154
            r#"{"stuff": "nonsense", "this": {"that": "the other"}}"#,
155
        ] {
156
            let _obj: JsonAnyObj = serde_json::from_str(ok).unwrap();
157
        }
158
    }
159
    #[test]
160
    fn any_obj_bad() {
161
        for bad in [r"[]", r#"7"#, r#"ksldjfa"#, r#""#, r#"{7:"foo"}"#] {
162
            let err: Result<JsonAnyObj, _> = serde_json::from_str(bad);
163
            assert!(err.is_err());
164
        }
165
    }
166
}