rust_release/
lib.rs

1//! # rust-release
2//!
3//! The [`rust-release`] crate defines a set of types which model a Rust release.
4//!
5//! This project is part of the [`rust-releases`] and [`cargo-msrv`] projects.
6//!
7//! In case you have a feature request, question, bug, or have another reason to
8//! contact the developers, please create a new issue at the `rust-releases`
9//! [`repository`].
10//!
11//! [`rust-releases`]: https://github.com/foresterre/rust-releases
12//! [`cargo-msrv`]: https://github.com/foresterre/cargo-msrv
13//! [`repository`]: https://github.com/foresterre/rust-releases/issues
14// #![deny(missing_docs)]
15#![warn(clippy::all)]
16#![deny(unsafe_code)]
17#![deny(missing_docs)]
18
19/// Type to model a Rust release.
20#[derive(Clone, Debug, Eq, PartialEq)]
21pub struct RustRelease {
22    version: ReleaseVersion,
23    release_date: Option<rust_toolchain::Date>,
24    toolchains: Vec<ExtendedToolchain>,
25}
26
27impl RustRelease {
28    /// Create a new RustRelease instance using a version, optionally
29    /// a release date, and an iterator of toolchains.
30    pub fn new(
31        version: ReleaseVersion,
32        release_date: Option<rust_toolchain::Date>,
33        toolchains: impl IntoIterator<Item = ExtendedToolchain>,
34    ) -> Self {
35        Self {
36            version,
37            release_date,
38            toolchains: toolchains.into_iter().collect(),
39        }
40    }
41
42    /// The 3 component MAJOR.MINOR.PATCH version number of the release
43    pub fn version(&self) -> &ReleaseVersion {
44        &self.version
45    }
46
47    /// Release date of the Rust release, if known
48    pub fn release_date(&self) -> Option<&rust_toolchain::Date> {
49        self.release_date.as_ref()
50    }
51
52    /// Toolchains associated with the release
53    pub fn toolchains(&self) -> impl Iterator<Item = &ExtendedToolchain> {
54        self.toolchains.iter()
55    }
56}
57
58/// A combination of a channel and the version number.
59///
60/// For stable and beta releases, we have a three component MAJOR.MINOR.PATCH
61/// version number. For nightly releases, we have a release date.
62#[derive(Clone, Debug, Eq, PartialEq)]
63pub enum ReleaseVersion {
64    /// A stable channel release version
65    Stable(rust_toolchain::channel::Stable),
66    /// A beta channel release version
67    Beta(rust_toolchain::channel::Beta),
68    /// A nightly channel release version
69    Nightly(rust_toolchain::channel::Nightly),
70}
71
72/// Type to model a Rust toolchain, with additional metadata relevant to a
73/// release.
74#[derive(Clone, Debug, Eq, PartialEq)]
75pub struct ExtendedToolchain {
76    toolchain: rust_toolchain::Toolchain,
77    tier: TargetTier,
78}
79
80impl ExtendedToolchain {
81    /// Create an ExtendedToolchain from a rust_toolchain::Toolchain
82    pub fn new(toolchain: rust_toolchain::Toolchain, tier: TargetTier) -> Self {
83        Self { toolchain, tier }
84    }
85
86    /// Get the toolchain
87    pub fn toolchain(&self) -> &rust_toolchain::Toolchain {
88        &self.toolchain
89    }
90
91    /// Get the toolchain tier
92    pub fn tier(&self) -> TargetTier {
93        self.tier
94    }
95}
96
97/// Support tier for a target
98#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
99pub enum TargetTier {
100    /// Tier 1 target
101    T1,
102    /// Tier 2 target
103    T2,
104    /// Tier 2.5 target
105    T2_5,
106    /// Tier 3 target
107    T3,
108    /// Tier is unknown
109    Unknown,
110}
111
112#[cfg(test)]
113mod tests {
114    use super::*;
115    use std::collections::HashSet;
116
117    #[test]
118    fn can_instantiate() {
119        let stable_version = rust_toolchain::channel::Stable {
120            version: rust_toolchain::RustVersion::new(1, 82, 0),
121        };
122        let version = ReleaseVersion::Stable(stable_version.clone());
123
124        let release = RustRelease::new(
125            version,
126            None,
127            vec![ExtendedToolchain::new(
128                rust_toolchain::Toolchain::new(
129                    rust_toolchain::Channel::Stable(stable_version.clone()),
130                    None,
131                    rust_toolchain::Target::host(),
132                    HashSet::new(),
133                    HashSet::new(),
134                ),
135                TargetTier::Unknown,
136            )],
137        );
138
139        let release_version = release.version();
140        assert_eq!(release_version, &ReleaseVersion::Stable(stable_version));
141    }
142
143    #[yare::parameterized(
144        some = { Some(rust_toolchain::Date::new(2024, 1, 1)) },
145        none = { None },
146    )]
147    fn can_instantiate_deux(date: Option<rust_toolchain::Date>) {
148        let stable_version = rust_toolchain::channel::Stable {
149            version: rust_toolchain::RustVersion::new(1, 82, 0),
150        };
151        let version = ReleaseVersion::Stable(stable_version.clone());
152
153        let release = RustRelease::new(
154            version,
155            date.clone(),
156            vec![ExtendedToolchain::new(
157                rust_toolchain::Toolchain::new(
158                    rust_toolchain::Channel::Stable(stable_version.clone()),
159                    date,
160                    rust_toolchain::Target::host(),
161                    HashSet::new(),
162                    HashSet::new(),
163                ),
164                TargetTier::Unknown,
165            )],
166        );
167
168        let release_date = release.release_date();
169        let target_date = release.toolchains().next().unwrap().toolchain().date();
170
171        assert_eq!(release_date, target_date);
172    }
173}