1use std::fmt;
2
3#[derive(Debug, PartialEq, Eq, Copy, Clone)]
4enum Kind {
5    Dev,
6    Nightly,
7    Beta,
8    Stable,
9}
10
11/// Release channel: "dev", "nightly", "beta", or "stable".
12#[derive(Debug, PartialEq, Eq, Copy, Clone)]
13pub struct Channel(Kind);
14
15impl Channel {
16    /// Reads the release channel of the running compiler. If it cannot be
17    /// determined (see the [top-level documentation](crate)), returns `None`.
18    ///
19    /// # Example
20    ///
21    /// ```rust
22    /// use version_check::Channel;
23    ///
24    /// match Channel::read() {
25    ///     Some(c) => format!("The channel is: {}", c),
26    ///     None => format!("Failed to read the release channel.")
27    /// };
28    /// ```
29    pub fn read() -> Option<Channel> {
30        ::get_version_and_date()
31            .and_then(|(version, _)| version)
32            .and_then(|version| Channel::parse(&version))
33    }
34
35    /// Parse a Rust release channel from a Rust release version string (of the
36    /// form `major[.minor[.patch[-channel]]]`). Returns `None` if `version` is
37    /// not a valid Rust version string.
38    ///
39    /// # Example
40    ///
41    /// ```rust
42    /// use version_check::Channel;
43    ///
44    /// let dev = Channel::parse("1.3.0-dev").unwrap();
45    /// assert!(dev.is_dev());
46    ///
47    /// let nightly = Channel::parse("1.42.2-nightly").unwrap();
48    /// assert!(nightly.is_nightly());
49    ///
50    /// let beta = Channel::parse("1.32.0-beta").unwrap();
51    /// assert!(beta.is_beta());
52    ///
53    /// let stable = Channel::parse("1.4.0").unwrap();
54    /// assert!(stable.is_stable());
55    /// ```
56    pub fn parse(version: &str) -> Option<Channel> {
57        let version = version.trim();
58        if version.contains("-dev") || version == "dev" {
59            Some(Channel(Kind::Dev))
60        } else if version.contains("-nightly") || version == "nightly" {
61            Some(Channel(Kind::Nightly))
62        } else if version.contains("-beta") || version == "beta" {
63            Some(Channel(Kind::Beta))
64        } else if !version.contains("-") {
65            Some(Channel(Kind::Stable))
66        } else {
67            None
68        }
69    }
70
71    /// Returns the name of the release channel.
72    fn as_str(&self) -> &'static str {
73        match self.0 {
74            Kind::Dev => "dev",
75            Kind::Beta => "beta",
76            Kind::Nightly => "nightly",
77            Kind::Stable => "stable",
78        }
79    }
80
81    /// Returns `true` if this channel supports feature flags. In other words,
82    /// returns `true` if the channel is either `dev` or `nightly`.
83    ///
84    /// # Example
85    ///
86    /// ```rust
87    /// use version_check::Channel;
88    ///
89    /// let dev = Channel::parse("1.3.0-dev").unwrap();
90    /// assert!(dev.supports_features());
91    ///
92    /// let nightly = Channel::parse("1.42.2-nightly").unwrap();
93    /// assert!(nightly.supports_features());
94    ///
95    /// let beta = Channel::parse("1.32.0-beta").unwrap();
96    /// assert!(!beta.supports_features());
97    ///
98    /// let stable = Channel::parse("1.4.0").unwrap();
99    /// assert!(!stable.supports_features());
100    /// ```
101    pub fn supports_features(&self) -> bool {
102        match self.0 {
103            Kind::Dev | Kind::Nightly => true,
104            Kind::Beta | Kind::Stable => false
105        }
106    }
107
108    /// Returns `true` if this channel is `dev` and `false` otherwise.
109    ///
110    /// # Example
111    ///
112    /// ```rust
113    /// use version_check::Channel;
114    ///
115    /// let dev = Channel::parse("1.3.0-dev").unwrap();
116    /// assert!(dev.is_dev());
117    ///
118    /// let stable = Channel::parse("1.0.0").unwrap();
119    /// assert!(!stable.is_dev());
120    /// ```
121    pub fn is_dev(&self) -> bool {
122        match self.0 {
123            Kind::Dev => true,
124            _ => false
125        }
126    }
127
128    /// Returns `true` if this channel is `nightly` and `false` otherwise.
129    ///
130    /// # Example
131    ///
132    /// ```rust
133    /// use version_check::Channel;
134    ///
135    /// let nightly = Channel::parse("1.3.0-nightly").unwrap();
136    /// assert!(nightly.is_nightly());
137    ///
138    /// let stable = Channel::parse("1.0.0").unwrap();
139    /// assert!(!stable.is_nightly());
140    /// ```
141    pub fn is_nightly(&self) -> bool {
142        match self.0 {
143            Kind::Nightly => true,
144            _ => false
145        }
146    }
147
148    /// Returns `true` if this channel is `beta` and `false` otherwise.
149    ///
150    /// # Example
151    ///
152    /// ```rust
153    /// use version_check::Channel;
154    ///
155    /// let beta = Channel::parse("1.3.0-beta").unwrap();
156    /// assert!(beta.is_beta());
157    ///
158    /// let stable = Channel::parse("1.0.0").unwrap();
159    /// assert!(!stable.is_beta());
160    /// ```
161    pub fn is_beta(&self) -> bool {
162        match self.0 {
163            Kind::Beta => true,
164            _ => false
165        }
166    }
167
168    /// Returns `true` if this channel is `stable` and `false` otherwise.
169    ///
170    /// # Example
171    ///
172    /// ```rust
173    /// use version_check::Channel;
174    ///
175    /// let stable = Channel::parse("1.0.0").unwrap();
176    /// assert!(stable.is_stable());
177    ///
178    /// let beta = Channel::parse("1.3.0-beta").unwrap();
179    /// assert!(!beta.is_stable());
180    /// ```
181    pub fn is_stable(&self) -> bool {
182        match self.0 {
183            Kind::Stable => true,
184            _ => false
185        }
186    }
187}
188
189impl fmt::Display for Channel {
190    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
191        write!(f, "{}", self.as_str())
192    }
193}
194