use std::{ convert::TryFrom, fmt::{self, Display}, str::FromStr, }; use http::Method; use crate::{error::UnknownVersionError, AuthScheme}; /// Metadata about an API endpoint. #[derive(Clone, Debug)] #[allow(clippy::exhaustive_structs)] pub struct Metadata { /// A human-readable description of the endpoint. pub description: &'static str, /// The HTTP method used by this endpoint. pub method: Method, /// A unique identifier for this endpoint. pub name: &'static str, /// The unstable path of this endpoint's URL, often `None`, used for developmental /// purposes. pub unstable_path: Option<&'static str>, /// The pre-v1.1 version of this endpoint's URL, `None` for post-v1.1 endpoints, /// supplemental to `stable_path`. pub r0_path: Option<&'static str>, /// The path of this endpoint's URL, with variable names where path parameters should be /// filled in during a request. pub stable_path: Option<&'static str>, /// Whether or not this endpoint is rate limited by the server. pub rate_limited: bool, /// What authentication scheme the server uses for this endpoint. pub authentication: AuthScheme, /// The matrix version that this endpoint was added in. /// /// Is None when this endpoint is unstable/unreleased. pub added: Option, /// The matrix version that deprecated this endpoint. /// /// Deprecation often precedes one matrix version before removal. /// /// This will make [`try_into_http_request`](crate::OutgoingRequest::try_into_http_request) /// emit a warning, see the corresponding documentation for more information. pub deprecated: Option, /// The matrix version that removed this endpoint. /// /// This will make [`try_into_http_request`](crate::OutgoingRequest::try_into_http_request) /// emit an error, see the corresponding documentation for more information. pub removed: Option, } /// 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: . /// /// 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 versions you /// pass to [`try_into_http_request`](crate::OutgoingRequest::try_into_http_request), see its /// respective documentation for more information. #[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 . V1_0, /// Version 1.1 of the Matrix specification, released in Q4 2021. /// /// See . V1_1, /// Version 1.2 of the Matrix specification, released in Q1 2022. /// /// See . V1_2, } impl TryFrom<&str> for MatrixVersion { type Error = UnknownVersionError; fn try_from(value: &str) -> Result { 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 FromStr for MatrixVersion { type Err = UnknownVersionError; fn from_str(s: &str) -> Result { Self::try_from(s) } } impl MatrixVersion { /// Checks whether 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 { let (major_l, minor_l) = self.into_parts(); let (major_r, minor_r) = other.into_parts(); major_l == major_r && minor_l >= minor_r } /// Decompose the Matrix version into its major and minor number. pub fn into_parts(self) -> (u8, u8) { match self { MatrixVersion::V1_0 => (1, 0), MatrixVersion::V1_1 => (1, 1), MatrixVersion::V1_2 => (1, 2), } } /// Try to turn a pair of (major, minor) version components back into a `MatrixVersion`. pub fn from_parts(major: u8, minor: u8) -> Result { match (major, minor) { (1, 0) => Ok(MatrixVersion::V1_0), (1, 1) => Ok(MatrixVersion::V1_1), (1, 2) => Ok(MatrixVersion::V1_2), _ => Err(UnknownVersionError), } } } impl Display for MatrixVersion { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (major, minor) = self.into_parts(); f.write_str(&format!("v{}.{}", major, minor)) } }