ruma_api/
metadata.rs

1use std::{
2    convert::TryFrom,
3    fmt::{self, Display},
4    str::FromStr,
5};
6
7use http::Method;
8
9use crate::{error::UnknownVersionError, AuthScheme};
10
11/// Metadata about an API endpoint.
12#[derive(Clone, Debug)]
13#[allow(clippy::exhaustive_structs)]
14pub struct Metadata {
15    /// A human-readable description of the endpoint.
16    pub description: &'static str,
17
18    /// The HTTP method used by this endpoint.
19    pub method: Method,
20
21    /// A unique identifier for this endpoint.
22    pub name: &'static str,
23
24    /// The unstable path of this endpoint's URL, often `None`, used for developmental
25    /// purposes.
26    pub unstable_path: Option<&'static str>,
27
28    /// The pre-v1.1 version of this endpoint's URL, `None` for post-v1.1 endpoints,
29    /// supplemental to `stable_path`.
30    pub r0_path: Option<&'static str>,
31
32    /// The path of this endpoint's URL, with variable names where path parameters should be
33    /// filled in during a request.
34    pub stable_path: Option<&'static str>,
35
36    /// Whether or not this endpoint is rate limited by the server.
37    pub rate_limited: bool,
38
39    /// What authentication scheme the server uses for this endpoint.
40    pub authentication: AuthScheme,
41
42    /// The matrix version that this endpoint was added in.
43    ///
44    /// Is None when this endpoint is unstable/unreleased.
45    pub added: Option<MatrixVersion>,
46
47    /// The matrix version that deprecated this endpoint.
48    ///
49    /// Deprecation often precedes one matrix version before removal.
50    ///
51    /// This will make [`try_into_http_request`](crate::OutgoingRequest::try_into_http_request)
52    /// emit a warning, see the corresponding documentation for more information.
53    pub deprecated: Option<MatrixVersion>,
54
55    /// The matrix version that removed this endpoint.
56    ///
57    /// This will make [`try_into_http_request`](crate::OutgoingRequest::try_into_http_request)
58    /// emit an error, see the corresponding documentation for more information.
59    pub removed: Option<MatrixVersion>,
60}
61
62/// The Matrix versions Ruma currently understands to exist.
63///
64/// Matrix, since fall 2021, has a quarterly release schedule, using a global `vX.Y` versioning
65/// scheme.
66///
67/// Every new minor version denotes stable support for endpoints in a *relatively*
68/// backwards-compatible manner.
69///
70/// Matrix has a deprecation policy, read more about it here: <https://spec.matrix.org/v1.2/#deprecation-policy>.
71///
72/// Ruma keeps track of when endpoints are added, deprecated, and removed. It'll automatically
73/// select the right endpoint stability variation to use depending on which Matrix versions you
74/// pass to [`try_into_http_request`](crate::OutgoingRequest::try_into_http_request), see its
75/// respective documentation for more information.
76#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
77#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
78pub enum MatrixVersion {
79    /// Version 1.0 of the Matrix specification.
80    ///
81    /// Retroactively defined as <https://spec.matrix.org/v1.2/#legacy-versioning>.
82    V1_0,
83
84    /// Version 1.1 of the Matrix specification, released in Q4 2021.
85    ///
86    /// See <https://spec.matrix.org/v1.1/>.
87    V1_1,
88
89    /// Version 1.2 of the Matrix specification, released in Q1 2022.
90    ///
91    /// See <https://spec.matrix.org/v1.2/>.
92    V1_2,
93}
94
95impl TryFrom<&str> for MatrixVersion {
96    type Error = UnknownVersionError;
97
98    fn try_from(value: &str) -> Result<MatrixVersion, Self::Error> {
99        use MatrixVersion::*;
100
101        Ok(match value {
102            // FIXME: these are likely not entirely correct; https://github.com/ruma/ruma/issues/852
103            "v1.0" |
104            // Additional definitions according to https://spec.matrix.org/v1.2/#legacy-versioning
105            "r0.5.0" | "r0.6.0" | "r0.6.1" => V1_0,
106            "v1.1" => V1_1,
107            "v1.2" => V1_2,
108            _ => return Err(UnknownVersionError),
109        })
110    }
111}
112
113impl FromStr for MatrixVersion {
114    type Err = UnknownVersionError;
115
116    fn from_str(s: &str) -> Result<Self, Self::Err> {
117        Self::try_from(s)
118    }
119}
120
121impl MatrixVersion {
122    /// Checks whether a version is compatible with another.
123    ///
124    /// A is compatible with B as long as B is equal or less, so long as A and B have the same
125    /// major versions.
126    ///
127    /// For example, v1.2 is compatible with v1.1, as it is likely only some additions of
128    /// endpoints on top of v1.1, but v1.1 would not be compatible with v1.2, as v1.1
129    /// cannot represent all of v1.2, in a manner similar to set theory.
130    ///
131    /// Warning: Matrix has a deprecation policy, and Matrix versioning is not as
132    /// straight-forward as this function makes it out to be. This function only exists
133    /// to prune major version differences, and versions too new for `self`.
134    ///
135    /// This (considering if major versions are the same) is equivalent to a `self >= other`
136    /// check.
137    pub fn is_superset_of(self, other: Self) -> bool {
138        let (major_l, minor_l) = self.into_parts();
139        let (major_r, minor_r) = other.into_parts();
140        major_l == major_r && minor_l >= minor_r
141    }
142
143    /// Decompose the Matrix version into its major and minor number.
144    pub fn into_parts(self) -> (u8, u8) {
145        match self {
146            MatrixVersion::V1_0 => (1, 0),
147            MatrixVersion::V1_1 => (1, 1),
148            MatrixVersion::V1_2 => (1, 2),
149        }
150    }
151
152    /// Try to turn a pair of (major, minor) version components back into a `MatrixVersion`.
153    pub fn from_parts(major: u8, minor: u8) -> Result<Self, UnknownVersionError> {
154        match (major, minor) {
155            (1, 0) => Ok(MatrixVersion::V1_0),
156            (1, 1) => Ok(MatrixVersion::V1_1),
157            (1, 2) => Ok(MatrixVersion::V1_2),
158            _ => Err(UnknownVersionError),
159        }
160    }
161}
162
163impl Display for MatrixVersion {
164    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
165        let (major, minor) = self.into_parts();
166        f.write_str(&format!("v{}.{}", major, minor))
167    }
168}