cuprate/rpc/json-rpc/src/version.rs
hinto-janai 4b93dbec4c
Some checks failed
CI / fmt (push) Waiting to run
CI / typo (push) Waiting to run
CI / ci (macos-latest, stable, bash) (push) Waiting to run
CI / ci (ubuntu-latest, stable, bash) (push) Waiting to run
CI / ci (windows-latest, stable-x86_64-pc-windows-gnu, msys2 {0}) (push) Waiting to run
Audit / audit (push) Has been cancelled
Deny / audit (push) Has been cancelled
workspace: enforce crate/directory naming scheme (#164)
* rename all directories and crates

* fix all `use`

* fix doc link

* `dandelion/` -> `dandelion-tower/`

* fix epee-encoding test

* fix `json-rpc`

* fix pruning

* crate import fixes

* fix leftover merge conflicts

* fix `epee-encoding`
2024-06-24 02:30:47 +01:00

119 lines
4.1 KiB
Rust

//! [`Version`]: JSON-RPC 2.0 version marker.
//---------------------------------------------------------------------------------------------------- Use
use serde::de::{Error, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
//---------------------------------------------------------------------------------------------------- Version
/// [Protocol version marker](https://www.jsonrpc.org/specification#compatibility).
///
/// This represents the JSON-RPC version.
///
/// This is an empty marker type that always gets (de)serialized as [`Self::TWO`].
///
/// It is the only valid value for the `jsonrpc` field in the
/// [`Request`](crate::Request) and [`Response`](crate::Request) objects.
///
/// JSON-RPC 2.0 allows for backwards compatibility with `1.0` but this crate
/// (and this type) will not accept that, and will fail in deserialization
/// when encountering anything but [`Self::TWO`].
///
/// # Formatting
/// When using Rust formatting, [`Version`] is formatted as `2.0`.
///
/// When using JSON serialization, `Version` is formatted with quotes indicating
/// it is a JSON string and not a JSON float, i.e. it gets formatted as `"2.0"`, not `2.0`.
///
/// # Example
/// ```rust
/// use cuprate_json_rpc::Version;
/// use serde_json::{to_string, to_string_pretty, from_str};
///
/// assert_eq!(Version::TWO, "2.0");
/// let version = Version;
///
/// // All debug/display formats are the same.
/// assert_eq!(format!("{version:?}"), Version::TWO);
/// assert_eq!(format!("{version:#?}"), Version::TWO);
/// assert_eq!(format!("{version}"), Version::TWO);
///
/// // JSON serialization will add extra quotes to
/// // indicate it is a string and not a float.
/// assert_eq!(to_string(&Version).unwrap(), "\"2.0\"");
/// assert_eq!(to_string_pretty(&Version).unwrap(), "\"2.0\"");
///
/// // Deserialization only accepts the JSON string "2.0".
/// assert!(from_str::<Version>(&"\"2.0\"").is_ok());
/// // This is JSON float, not a string.
/// assert!(from_str::<Version>(&"2.0").is_err());
///
/// assert!(from_str::<Version>(&"2").is_err());
/// assert!(from_str::<Version>(&"1.0").is_err());
/// assert!(from_str::<Version>(&"20").is_err());
/// assert!(from_str::<Version>(&"two").is_err());
/// assert!(from_str::<Version>(&"2.1").is_err());
/// assert!(from_str::<Version>(&"v2.0").is_err());
/// assert!(from_str::<Version>("").is_err());
/// ```
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Version;
impl Version {
/// The string `2.0`.
///
/// Note that this does not have extra quotes to mark
/// that it's a JSON string and not a float.
/// ```rust
/// use cuprate_json_rpc::Version;
///
/// let string = format!("{}", Version);
/// assert_eq!(string, "2.0");
/// assert_ne!(string, "\"2.0\"");
/// ```
pub const TWO: &'static str = "2.0";
}
//---------------------------------------------------------------------------------------------------- Trait impl
impl Serialize for Version {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
s.serialize_str(Self::TWO)
}
}
impl std::fmt::Display for Version {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, r#"{}"#, Self::TWO)
}
}
impl std::fmt::Debug for Version {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, r#"{}"#, Self::TWO)
}
}
//---------------------------------------------------------------------------------------------------- Serde impl
/// Empty serde visitor for [`Version`].
struct VersionVisitor;
impl Visitor<'_> for VersionVisitor {
type Value = Version;
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.write_str("Identifier must be the exact string: \"2.0\"")
}
fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
if v == Version::TWO {
Ok(Version)
} else {
Err(Error::invalid_value(serde::de::Unexpected::Str(v), &self))
}
}
}
impl<'de> Deserialize<'de> for Version {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
d.deserialize_str(VersionVisitor)
}
}