Skip to main content

rucc_tuple/
error.rs

1//! What goes wrong when a tuple is read, and what the user is told about it.
2
3use core::fmt;
4
5use crate::{Abi, Arch, Endian, Env, Os, SubArch};
6
7/// A tuple that could not be read, or that was read and does not describe a machine.
8///
9/// Every variant names the component it is unhappy about. That is the whole design goal of this
10/// type: the model this replaces had a catch-all arm that skipped anything it did not recognize,
11/// so `x86_64-linux-gnu.2.28` parsed as `x86_64-linux-gnu` and the version was thrown away with
12/// no diagnostic. A user who pins a glibc version and gets the host's is not going to find out
13/// until the binary fails on the target machine.
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub enum Error {
16    /// The tuple was empty or all separators.
17    Empty,
18    /// The leading component is not an architecture we know.
19    UnknownArch(String),
20    /// The OS component is not an OS we know.
21    UnknownOs(String),
22    /// The environment component is not an environment we know.
23    UnknownEnv(String),
24    /// Components were left over after the environment was read.
25    ///
26    /// This is the case the old catch-all silently ate, so it is an error with the leftovers
27    /// quoted rather than a shrug.
28    Trailing(Vec<String>),
29    /// A version was attached to a component and could not be read as one.
30    BadVersion {
31        /// The component the version was attached to, for the message.
32        component: &'static str,
33        /// What was found where a version was expected.
34        found: String,
35    },
36    /// A sub-architecture was named that does not belong to the architecture.
37    SubArchMismatch {
38        /// The architecture that was named.
39        arch: Arch,
40        /// The baseline that does not belong to it.
41        sub_arch: SubArch,
42    },
43    /// A byte order was named that the architecture does not have.
44    EndianUnsupported {
45        /// The architecture that was named.
46        arch: Arch,
47        /// The byte order it does not have.
48        endian: Endian,
49    },
50    /// An environment was named that the OS does not have.
51    EnvMismatch {
52        /// The OS that was named.
53        os: Os,
54        /// The environment it does not have.
55        env: Env,
56    },
57    /// A float ABI was named for an architecture that has one calling convention.
58    AbiMismatch {
59        /// The architecture that was named.
60        arch: Arch,
61        /// The ABI it cannot select.
62        abi: Abi,
63    },
64    /// A version was attached to a component that does not take one.
65    ///
66    /// `x86_64-linux.5.15-gnu` is not a request for a kernel version, it is a mistake, and
67    /// accepting it would mean the tuple carries a field nothing reads.
68    VersionNotAccepted {
69        /// The component the version was attached to.
70        component: &'static str,
71    },
72}
73
74impl fmt::Display for Error {
75    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76        match self {
77            Error::Empty => write!(f, "empty target tuple"),
78            Error::UnknownArch(found) => {
79                write!(f, "unknown architecture `{found}`")
80            }
81            Error::UnknownOs(found) => write!(f, "unknown operating system `{found}`"),
82            Error::UnknownEnv(found) => write!(f, "unknown environment `{found}`"),
83            Error::Trailing(rest) => {
84                write!(f, "unexpected trailing component")?;
85                if rest.len() > 1 {
86                    f.write_str("s")?;
87                }
88                for (i, part) in rest.iter().enumerate() {
89                    if i == 0 {
90                        write!(f, " `{part}`")?;
91                    } else {
92                        write!(f, ", `{part}`")?;
93                    }
94                }
95                Ok(())
96            }
97            Error::BadVersion { component, found } => {
98                write!(f, "`{found}` is not a version for the {component} component")
99            }
100            Error::SubArchMismatch { arch, sub_arch } => {
101                write!(f, "`{}` is not a baseline of `{arch}`", sub_arch.as_str())
102            }
103            Error::EndianUnsupported { arch, endian } => {
104                write!(f, "`{arch}` has no {endian} endian mode")
105            }
106            Error::EnvMismatch { os, env } => {
107                write!(f, "`{os}` has no `{env}` environment")
108            }
109            Error::AbiMismatch { arch, abi } => {
110                write!(f, "`{arch}` has one calling convention and cannot select `{abi}`")
111            }
112            Error::VersionNotAccepted { component } => {
113                write!(f, "the {component} component does not take a version")
114            }
115        }
116    }
117}
118
119impl std::error::Error for Error {}