Skip to main content

rustc_target/spec/
tuple.rs

1use std::hash::{Hash, Hasher};
2use std::path::{Path, PathBuf};
3use std::{fmt, io};
4
5use rustc_error_messages::into_diag_arg_using_display;
6use rustc_fs_util::try_canonicalize;
7use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
8
9/// Either a target tuple string or a path to a JSON file.
10#[derive(#[automatically_derived]
impl ::core::clone::Clone for TargetTuple {
    #[inline]
    fn clone(&self) -> TargetTuple {
        match self {
            TargetTuple::TargetTuple(__self_0) =>
                TargetTuple::TargetTuple(::core::clone::Clone::clone(__self_0)),
            TargetTuple::TargetJson {
                path_for_rustdoc: __self_0,
                tuple: __self_1,
                contents: __self_2 } =>
                TargetTuple::TargetJson {
                    path_for_rustdoc: ::core::clone::Clone::clone(__self_0),
                    tuple: ::core::clone::Clone::clone(__self_1),
                    contents: ::core::clone::Clone::clone(__self_2),
                },
        }
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for TargetTuple {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            TargetTuple::TargetTuple(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "TargetTuple", &__self_0),
            TargetTuple::TargetJson {
                path_for_rustdoc: __self_0,
                tuple: __self_1,
                contents: __self_2 } =>
                ::core::fmt::Formatter::debug_struct_field3_finish(f,
                    "TargetJson", "path_for_rustdoc", __self_0, "tuple",
                    __self_1, "contents", &__self_2),
        }
    }
}Debug)]
11pub enum TargetTuple {
12    TargetTuple(String),
13    TargetJson {
14        /// Warning: This field may only be used by rustdoc. Using it anywhere else will lead to
15        /// inconsistencies as it is discarded during serialization.
16        path_for_rustdoc: PathBuf,
17        tuple: String,
18        contents: String,
19    },
20}
21
22// Use a manual implementation to ignore the path field
23impl PartialEq for TargetTuple {
24    fn eq(&self, other: &Self) -> bool {
25        match (self, other) {
26            (Self::TargetTuple(l0), Self::TargetTuple(r0)) => l0 == r0,
27            (
28                Self::TargetJson { path_for_rustdoc: _, tuple: l_tuple, contents: l_contents },
29                Self::TargetJson { path_for_rustdoc: _, tuple: r_tuple, contents: r_contents },
30            ) => l_tuple == r_tuple && l_contents == r_contents,
31            _ => false,
32        }
33    }
34}
35
36// Use a manual implementation to ignore the path field
37impl Hash for TargetTuple {
38    fn hash<H: Hasher>(&self, state: &mut H) -> () {
39        match self {
40            TargetTuple::TargetTuple(tuple) => {
41                0u8.hash(state);
42                tuple.hash(state)
43            }
44            TargetTuple::TargetJson { path_for_rustdoc: _, tuple, contents } => {
45                1u8.hash(state);
46                tuple.hash(state);
47                contents.hash(state)
48            }
49        }
50    }
51}
52
53// Use a manual implementation to prevent encoding the target json file path in the crate metadata
54impl<S: Encoder> Encodable<S> for TargetTuple {
55    fn encode(&self, s: &mut S) {
56        match self {
57            TargetTuple::TargetTuple(tuple) => {
58                s.emit_u8(0);
59                s.emit_str(tuple);
60            }
61            TargetTuple::TargetJson { path_for_rustdoc: _, tuple, contents } => {
62                s.emit_u8(1);
63                s.emit_str(tuple);
64                s.emit_str(contents);
65            }
66        }
67    }
68}
69
70impl<D: Decoder> Decodable<D> for TargetTuple {
71    fn decode(d: &mut D) -> Self {
72        match d.read_u8() {
73            0 => TargetTuple::TargetTuple(d.read_str().to_owned()),
74            1 => TargetTuple::TargetJson {
75                path_for_rustdoc: PathBuf::new(),
76                tuple: d.read_str().to_owned(),
77                contents: d.read_str().to_owned(),
78            },
79            _ => {
80                {
    ::core::panicking::panic_fmt(format_args!("invalid enum variant tag while decoding `TargetTuple`, expected 0..2"));
};panic!("invalid enum variant tag while decoding `TargetTuple`, expected 0..2");
81            }
82        }
83    }
84}
85
86impl TargetTuple {
87    /// Creates a target tuple from the passed target tuple string.
88    pub fn from_tuple(tuple: &str) -> Self {
89        TargetTuple::TargetTuple(tuple.into())
90    }
91
92    /// Creates a target tuple from the passed target path.
93    pub fn from_path(path: &Path) -> Result<Self, io::Error> {
94        let canonicalized_path = try_canonicalize(path)?;
95        let contents = std::fs::read_to_string(&canonicalized_path).map_err(|err| {
96            io::Error::new(
97                io::ErrorKind::InvalidInput,
98                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("target path {0:?} is not a valid file: {1}",
                canonicalized_path, err))
    })format!("target path {canonicalized_path:?} is not a valid file: {err}"),
99            )
100        })?;
101        let tuple = canonicalized_path
102            .file_stem()
103            .expect("target path must not be empty")
104            .to_str()
105            .expect("target path must be valid unicode")
106            .to_owned();
107        Ok(TargetTuple::TargetJson { path_for_rustdoc: canonicalized_path, tuple, contents })
108    }
109
110    /// Returns a string tuple for this target.
111    ///
112    /// If this target is a path, the file name (without extension) is returned.
113    pub fn tuple(&self) -> &str {
114        match *self {
115            TargetTuple::TargetTuple(ref tuple) | TargetTuple::TargetJson { ref tuple, .. } => {
116                tuple
117            }
118        }
119    }
120
121    /// Returns an extended string tuple for this target.
122    ///
123    /// If this target is a path, a hash of the path is appended to the tuple returned
124    /// by `tuple()`.
125    pub fn debug_tuple(&self) -> String {
126        use std::hash::DefaultHasher;
127
128        match self {
129            TargetTuple::TargetTuple(tuple) => tuple.to_owned(),
130            TargetTuple::TargetJson { path_for_rustdoc: _, tuple, contents: content } => {
131                let mut hasher = DefaultHasher::new();
132                content.hash(&mut hasher);
133                let hash = hasher.finish();
134                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}-{1}", tuple, hash))
    })format!("{tuple}-{hash}")
135            }
136        }
137    }
138}
139
140impl fmt::Display for TargetTuple {
141    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142        f.write_fmt(format_args!("{0}", self.debug_tuple()))write!(f, "{}", self.debug_tuple())
143    }
144}
145
146impl ::rustc_error_messages::IntoDiagArg for &TargetTuple {
    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>)
        -> ::rustc_error_messages::DiagArgValue {
        self.to_string().into_diag_arg(path)
    }
}into_diag_arg_using_display!(&TargetTuple);