rust_toolchain/
target.rs

1use std::fmt;
2use std::str::FromStr;
3
4/// A target platform
5///
6/// Commonly represented as a [`target triple`]. A target triple consists of three (or four) components: the
7/// architecture component, the vendor component, the operating system component and optionally
8/// a fourth component representing the environment (e.g. gnu or msvc).
9///
10/// # Reading materials
11///
12/// - [`RFC 0131: target specification`]
13/// - [`rustup concepts: toolchains`]
14/// - [`rustup component history`]
15/// - [`rustc platform support`]
16///
17/// [`target triple`]: https://github.com/rust-lang/rfcs/blob/master/text/0131-target-specification.md#detailed-design
18/// [`RFC 0131: target specification`]: https://github.com/rust-lang/rfcs/blob/master/text/0131-target-specification.md#detailed-design
19/// [`rustup concepts: toolchains`]: https://rust-lang.github.io/rustup/concepts/toolchains.html
20/// [`rustup component history`]: https://rust-lang.github.io/rustup-components-history/
21/// [`rustc platform support`]: https://doc.rust-lang.org/rustc/platform-support.html
22#[derive(Clone, Debug, Eq, Hash, PartialEq)]
23pub struct Target {
24    target: target_lexicon::Triple,
25}
26
27impl Target {
28    /// Create a new `Target` instance which represents the `host` platform.
29    ///
30    /// The platform on which this library is compiled, will be the `host` platform.
31    pub const fn host() -> Self {
32        Self {
33            target: target_lexicon::HOST,
34        }
35    }
36
37    /// Create a new `Target` instance from a [`target triple`].
38    ///
39    /// * See also: [Rustc platform support](https://doc.rust-lang.org/rustc/platform-support.html)
40    ///
41    /// [`target triple`]: https://github.com/rust-lang/rfcs/blob/master/text/0131-target-specification.md#detailed-design
42    pub fn try_from_target_triple(triple: &str) -> Result<Self, ParseError> {
43        let platform = target_lexicon::Triple::from_str(triple).map_err(ParseError::from)?;
44
45        Ok(Self { target: platform })
46    }
47
48    /// Create a new `Target` instance from a [`target triple`], defaults to
49    /// `unknown-unknown-unknown` if the give triple is not recognized.
50    ///
51    /// * See also: [Rustc platform support](https://doc.rust-lang.org/rustc/platform-support.html)
52    ///
53    /// [`target triple`]: https://github.com/rust-lang/rfcs/blob/master/text/0131-target-specification.md#detailed-design
54    pub fn from_target_triple_or_unknown(triple: &str) -> Self {
55        let platform = target_lexicon::Triple::from_str(triple)
56            .unwrap_or_else(|_| target_lexicon::Triple::unknown());
57
58        Self { target: platform }
59    }
60}
61
62impl fmt::Display for Target {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        write!(f, "{}", self.target)
65    }
66}
67
68/// Errors which may occur while parsing a [`Target`].
69#[derive(Debug, thiserror::Error)]
70#[non_exhaustive]
71pub enum ParseError {
72    #[error("Unknown architecture `{0}`")]
73    Architecture(String),
74    #[error("Unknown vendor `{0}`")]
75    Vendor(String),
76    #[error("Unknown operating system `{0}`")]
77    OperatingSystem(String),
78    #[error("Unknown environment `{0}`")]
79    Environment(String),
80    #[error("Unknown binary format `{0}`")]
81    BinaryFormat(String),
82    #[error("Unknown field `{0}`")]
83    Field(String),
84}
85
86impl From<target_lexicon::ParseError> for ParseError {
87    fn from(value: target_lexicon::ParseError) -> Self {
88        match value {
89            target_lexicon::ParseError::UnrecognizedArchitecture(v) => ParseError::Architecture(v),
90            target_lexicon::ParseError::UnrecognizedVendor(v) => ParseError::Vendor(v),
91            target_lexicon::ParseError::UnrecognizedOperatingSystem(v) => {
92                ParseError::OperatingSystem(v)
93            }
94            target_lexicon::ParseError::UnrecognizedEnvironment(v) => ParseError::Environment(v),
95            target_lexicon::ParseError::UnrecognizedBinaryFormat(v) => ParseError::BinaryFormat(v),
96            target_lexicon::ParseError::UnrecognizedField(v) => ParseError::Field(v),
97        }
98    }
99}
100
101#[cfg(test)]
102mod tests {
103    use super::*;
104
105    #[test]
106    fn create_platform() {
107        let this_platform = Target::host();
108
109        let expected = Target {
110            target: target_lexicon::HOST,
111        };
112
113        assert_eq!(this_platform, expected);
114    }
115
116    #[test]
117    fn to_string() {
118        let target = Target::try_from_target_triple("x86_64-unknown-linux-gnu").unwrap();
119
120        assert_eq!(target.to_string(), "x86_64-unknown-linux-gnu");
121    }
122}