cuprate_json_rpc/
version.rs

1//! [`Version`]: JSON-RPC 2.0 version marker.
2
3//---------------------------------------------------------------------------------------------------- Use
4use serde::de::{Error, Visitor};
5use serde::{Deserialize, Deserializer, Serialize, Serializer};
6
7//---------------------------------------------------------------------------------------------------- Version
8/// [Protocol version marker](https://www.jsonrpc.org/specification#compatibility).
9///
10/// This represents the JSON-RPC version.
11///
12/// This is an empty marker type that always gets (de)serialized as [`Self::TWO`].
13///
14/// It is the only valid value for the `jsonrpc` field in the
15/// [`Request`](crate::Request) and [`Response`](crate::Request) objects.
16///
17/// JSON-RPC 2.0 allows for backwards compatibility with `1.0` but this crate
18/// (and this type) will not accept that, and will fail in deserialization
19/// when encountering anything but [`Self::TWO`].
20///
21/// # Formatting
22/// When using Rust formatting, [`Version`] is formatted as `2.0`.
23///
24/// When using JSON serialization, `Version` is formatted with quotes indicating
25/// it is a JSON string and not a JSON float, i.e. it gets formatted as `"2.0"`, not `2.0`.
26///
27/// # Example
28/// ```rust
29/// use cuprate_json_rpc::Version;
30/// use serde_json::{to_string, to_string_pretty, from_str};
31///
32/// assert_eq!(Version::TWO, "2.0");
33/// let version = Version;
34///
35/// // All debug/display formats are the same.
36/// assert_eq!(format!("{version:?}"), Version::TWO);
37/// assert_eq!(format!("{version:#?}"), Version::TWO);
38/// assert_eq!(format!("{version}"), Version::TWO);
39///
40/// // JSON serialization will add extra quotes to
41/// // indicate it is a string and not a float.
42/// assert_eq!(to_string(&Version).unwrap(), "\"2.0\"");
43/// assert_eq!(to_string_pretty(&Version).unwrap(), "\"2.0\"");
44///
45/// // Deserialization only accepts the JSON string "2.0".
46/// assert!(from_str::<Version>(&"\"2.0\"").is_ok());
47/// // This is JSON float, not a string.
48/// assert!(from_str::<Version>(&"2.0").is_err());
49///
50/// assert!(from_str::<Version>(&"2").is_err());
51/// assert!(from_str::<Version>(&"1.0").is_err());
52/// assert!(from_str::<Version>(&"20").is_err());
53/// assert!(from_str::<Version>(&"two").is_err());
54/// assert!(from_str::<Version>(&"2.1").is_err());
55/// assert!(from_str::<Version>(&"v2.0").is_err());
56/// assert!(from_str::<Version>("").is_err());
57/// ```
58#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
59pub struct Version;
60
61impl Version {
62    /// The string `2.0`.
63    ///
64    /// Note that this does not have extra quotes to mark
65    /// that it's a JSON string and not a float.
66    /// ```rust
67    /// use cuprate_json_rpc::Version;
68    ///
69    /// let string = format!("{}", Version);
70    /// assert_eq!(string, "2.0");
71    /// assert_ne!(string, "\"2.0\"");
72    /// ```
73    pub const TWO: &'static str = "2.0";
74}
75
76//---------------------------------------------------------------------------------------------------- Trait impl
77impl Serialize for Version {
78    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
79        s.serialize_str(Self::TWO)
80    }
81}
82
83impl std::fmt::Display for Version {
84    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85        write!(f, "{}", Self::TWO)
86    }
87}
88
89impl std::fmt::Debug for Version {
90    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91        write!(f, "{}", Self::TWO)
92    }
93}
94
95//---------------------------------------------------------------------------------------------------- Serde impl
96/// Empty serde visitor for [`Version`].
97struct VersionVisitor;
98
99impl Visitor<'_> for VersionVisitor {
100    type Value = Version;
101
102    fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
103        f.write_str("Identifier must be the exact string: \"2.0\"")
104    }
105
106    fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
107        if v == Version::TWO {
108            Ok(Version)
109        } else {
110            Err(Error::invalid_value(serde::de::Unexpected::Str(v), &self))
111        }
112    }
113}
114
115impl<'de> Deserialize<'de> for Version {
116    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
117        d.deserialize_str(VersionVisitor)
118    }
119}