Skip to content

Commit

Permalink
rpc: Add FromStr, Serialize and Deserialize instances to `Compa…
Browse files Browse the repository at this point in the history
…tMode` (#1367)

* rpc: Add `FromStr`, `Serialize` and `Deserialize` instances to `CompatMode`

* Add changelog entry
  • Loading branch information
romac committed Mar 14, 2024
1 parent 3d31a60 commit 6e2baf2
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- `[tendermint-rpc]` Add `FromStr`, `Serialize` and `Deserialize` instances
to `CompatMode` ([\#1374](https://github.com/informalsystems/tendermint-
rs/issues/1374))
61 changes: 61 additions & 0 deletions rpc/src/client/compat.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
//! Support for dynamic compatibility with older protocol versions.

use core::fmt;
use core::str::FromStr;

use serde::{de::Deserializer, Deserialize, Serialize, Serializer};

use tendermint::Version;

Expand All @@ -14,6 +17,12 @@ pub enum CompatMode {
V0_34,
/// Use version 0.37 of the protocol.
V0_37,
// NOTE: When adding a newer version, do not forget to update:
// - CompatMode::latest()
// - CompatMode::from_version()
// - impl Display for CompatMode
// - impl FromStr for CompatMode
// - The tests
}

impl Default for CompatMode {
Expand Down Expand Up @@ -64,6 +73,45 @@ impl fmt::Display for CompatMode {
}
}

impl FromStr for CompatMode {
type Err = Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
const VALID_COMPAT_MODES: &str = "v0.34, v0.37";

// Trim leading 'v', if present
match s.trim_start_matches('v') {
"0.34" => Ok(CompatMode::V0_34),
"0.37" => Ok(CompatMode::V0_37),
_ => Err(Error::invalid_compat_mode(
s.to_string(),
VALID_COMPAT_MODES,
)),
}
}
}

impl<'de> Deserialize<'de> for CompatMode {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
use serde::de;

let s = String::deserialize(deserializer)?;
FromStr::from_str(&s).map_err(de::Error::custom)
}
}

impl Serialize for CompatMode {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.to_string().serialize(serializer)
}
}

#[cfg(test)]
mod tests {
use super::CompatMode;
Expand Down Expand Up @@ -100,4 +148,17 @@ mod tests {
let res = CompatMode::from_version(parse_version("poobah"));
assert!(res.is_err());
}

#[test]
fn test_from_str() {
assert_eq!("0.34".parse::<CompatMode>().unwrap(), CompatMode::V0_34);
assert_eq!("0.37".parse::<CompatMode>().unwrap(), CompatMode::V0_37);

let res = "0.33".parse::<CompatMode>();
assert!(res.is_err());
let res = "0.38".parse::<CompatMode>();
assert!(res.is_err());
let res = "foobar".parse::<CompatMode>();
assert!(res.is_err());
}
}
10 changes: 10 additions & 0 deletions rpc/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,16 @@ define_error! {
| e | {
format_args!("unsupported Tendermint version reported by the node: {}", e.version)
},

InvalidCompatMode
{
mode: String,
supported: &'static str,
}
| e | {
format_args!("invalid compatibility mode: '{}' (supported: {})",
e.mode, e.supported)
},
}
}

Expand Down

0 comments on commit 6e2baf2

Please sign in to comment.