api: Add MatrixVersion enum
Co-authored-by: Jonas Platte <jplatte@users.noreply.github.com>
This commit is contained in:
parent
9c4bf00f79
commit
19fd35d066
@ -18,7 +18,11 @@
|
|||||||
#[cfg(not(all(feature = "client", feature = "server")))]
|
#[cfg(not(all(feature = "client", feature = "server")))]
|
||||||
compile_error!("ruma_api's Cargo features only exist as a workaround are not meant to be disabled");
|
compile_error!("ruma_api's Cargo features only exist as a workaround are not meant to be disabled");
|
||||||
|
|
||||||
use std::{convert::TryInto as _, error::Error as StdError};
|
use std::{
|
||||||
|
convert::{TryFrom, TryInto as _},
|
||||||
|
error::Error as StdError,
|
||||||
|
fmt::{self, Display},
|
||||||
|
};
|
||||||
|
|
||||||
use bytes::BufMut;
|
use bytes::BufMut;
|
||||||
use http::Method;
|
use http::Method;
|
||||||
@ -421,3 +425,140 @@ pub struct Metadata {
|
|||||||
/// What authentication scheme the server uses for this endpoint.
|
/// What authentication scheme the server uses for this endpoint.
|
||||||
pub authentication: AuthScheme,
|
pub authentication: AuthScheme,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The Matrix versions Ruma currently understands to exist.
|
||||||
|
///
|
||||||
|
/// Matrix, since fall 2021, has a quarterly release schedule, using a global `vX.Y` versioning
|
||||||
|
/// scheme.
|
||||||
|
///
|
||||||
|
/// Every new minor version denotes stable support for endpoints in a *relatively*
|
||||||
|
/// backwards-compatible manner.
|
||||||
|
///
|
||||||
|
/// Matrix has a deprecation policy, read more about it here: <https://spec.matrix.org/v1.2/#deprecation-policy>.
|
||||||
|
// TODO add the following once `EndpointPath` and added/deprecated/removed macros are in place;
|
||||||
|
// Ruma keeps track of when endpoints are added, deprecated, and removed. It'll automatically
|
||||||
|
// select the right endpoint stability variation to use depending on which Matrix version you pass
|
||||||
|
// it with [`EndpointPath`], see its respective documentation for more.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||||
|
pub enum MatrixVersion {
|
||||||
|
/// Version 1.0 of the Matrix specification.
|
||||||
|
///
|
||||||
|
/// Retroactively defined as <https://spec.matrix.org/v1.1/#legacy-versioning>.
|
||||||
|
V1_0,
|
||||||
|
|
||||||
|
/// Version 1.1 of the Matrix specification, released in Q4 2021.
|
||||||
|
///
|
||||||
|
/// See <https://spec.matrix.org/v1.1/>.
|
||||||
|
V1_1,
|
||||||
|
|
||||||
|
/// Version 1.2 of the Matrix specification, released in Q1 2022.
|
||||||
|
///
|
||||||
|
/// See <https://spec.matrix.org/v1.2/>.
|
||||||
|
V1_2,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An error that happens when Ruma cannot understand a Matrix version.
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||||
|
pub struct UnknownVersionError;
|
||||||
|
|
||||||
|
impl Display for UnknownVersionError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "Version string was unknown.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StdError for UnknownVersionError {}
|
||||||
|
|
||||||
|
impl TryFrom<&str> for MatrixVersion {
|
||||||
|
type Error = UnknownVersionError;
|
||||||
|
|
||||||
|
fn try_from(value: &str) -> Result<MatrixVersion, Self::Error> {
|
||||||
|
use MatrixVersion::*;
|
||||||
|
|
||||||
|
Ok(match value {
|
||||||
|
// FIXME: these are likely not entirely correct; https://github.com/ruma/ruma/issues/852
|
||||||
|
"v1.0" |
|
||||||
|
// Additional definitions according to https://spec.matrix.org/v1.2/#legacy-versioning
|
||||||
|
"r0.5.0" | "r0.6.0" | "r0.6.1" => V1_0,
|
||||||
|
"v1.1" => V1_1,
|
||||||
|
"v1.2" => V1_2,
|
||||||
|
_ => return Err(UnknownVersionError),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for MatrixVersion {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let r = self.repr();
|
||||||
|
|
||||||
|
f.write_str(&format!("v{}.{}", r.major, r.minor))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal-only structure to abstract away version representations into Major-Minor bits.
|
||||||
|
//
|
||||||
|
// This is not represented on MatrixVersion due to the major footguns it exposes,
|
||||||
|
// maybe in the future this'll be merged into it, but not now.
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
struct VersionRepr {
|
||||||
|
major: u8,
|
||||||
|
minor: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VersionRepr {
|
||||||
|
fn new(major: u8, minor: u8) -> Self {
|
||||||
|
VersionRepr { major, minor }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't expose this on MatrixVersion due to the subtleties of non-total ordering semantics
|
||||||
|
// the Matrix versions have; we cannot guarantee ordering between major versions, and only between
|
||||||
|
// minor versions of the same major one.
|
||||||
|
//
|
||||||
|
// This means that V2_0 > V1_0 returns false, and V2_0 < V1_0 too.
|
||||||
|
//
|
||||||
|
// This sort of behavior has to be pre-emptively known by the programmer, which is the definition of
|
||||||
|
// a gotcha/footgun.
|
||||||
|
//
|
||||||
|
// As such, we're not including it in the public API (only using it via `MatrixVersion::compatible`)
|
||||||
|
// until we find a way to introduce it in a way that exposes the ambiguities to the programmer.
|
||||||
|
impl PartialOrd for VersionRepr {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
if self.major != other.major {
|
||||||
|
// Ordering between major versions is non-total.
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
self.minor.partial_cmp(&other.minor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MatrixVersion {
|
||||||
|
/// Checks wether a version is compatible with another.
|
||||||
|
///
|
||||||
|
/// A is compatible with B as long as B is equal or less, so long as A and B have the same major
|
||||||
|
/// versions.
|
||||||
|
///
|
||||||
|
/// For example, v1.2 is compatible with v1.1, as it is likely only some additions of endpoints
|
||||||
|
/// on top of v1.1, but v1.1 would not be compatible with v1.2, as v1.1 cannot represent all of
|
||||||
|
/// v1.2, in a manner similar to set theory.
|
||||||
|
///
|
||||||
|
/// Warning: Matrix has a deprecation policy, and Matrix versioning is not as straight-forward
|
||||||
|
/// as this function makes it out to be. This function only exists to prune major version
|
||||||
|
/// differences, and versions too new for `self`.
|
||||||
|
///
|
||||||
|
/// This (considering if major versions are the same) is equivalent to a `self >= other` check.
|
||||||
|
pub fn is_superset_of(self, other: Self) -> bool {
|
||||||
|
self.repr() >= other.repr()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal function to desugar the enum to a version repr
|
||||||
|
fn repr(&self) -> VersionRepr {
|
||||||
|
match self {
|
||||||
|
MatrixVersion::V1_0 => VersionRepr::new(1, 0),
|
||||||
|
MatrixVersion::V1_1 => VersionRepr::new(1, 1),
|
||||||
|
MatrixVersion::V1_2 => VersionRepr::new(1, 2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
//! [GET /_matrix/client/versions](https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-versions)
|
//! [GET /_matrix/client/versions](https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-versions)
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::{collections::BTreeMap, convert::TryInto as _};
|
||||||
|
|
||||||
use ruma_api::ruma_api;
|
use ruma_api::{ruma_api, MatrixVersion};
|
||||||
|
|
||||||
ruma_api! {
|
ruma_api! {
|
||||||
metadata: {
|
metadata: {
|
||||||
@ -41,4 +41,19 @@ impl Response {
|
|||||||
pub fn new(versions: Vec<String>) -> Self {
|
pub fn new(versions: Vec<String>) -> Self {
|
||||||
Self { versions, unstable_features: BTreeMap::new() }
|
Self { versions, unstable_features: BTreeMap::new() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extracts known Matrix versions from this response.
|
||||||
|
///
|
||||||
|
/// Matrix versions that Ruma cannot parse, or does not know about, are discarded.
|
||||||
|
pub fn known_versions(&self) -> Vec<MatrixVersion> {
|
||||||
|
let mut versions = vec![];
|
||||||
|
for s in &self.versions {
|
||||||
|
if let Ok(ver) = s.as_str().try_into() {
|
||||||
|
if !versions.contains(&ver) {
|
||||||
|
versions.push(ver)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
versions
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user