1 use crate::cfg::CFG; 2 use crate::gen::fs; 3 use std::error::Error as StdError; 4 use std::ffi::OsString; 5 use std::fmt::{self, Display}; 6 use std::path::Path; 7 8 pub(super) type Result<T, E = Error> = std::result::Result<T, E>; 9 10 #[derive(Debug)] 11 pub(super) enum Error { 12 NoEnv(OsString), 13 Fs(fs::Error), 14 ExportedDirNotAbsolute(&'static Path), 15 ExportedEmptyPrefix, 16 ExportedDirsWithoutLinks, 17 ExportedPrefixesWithoutLinks, 18 ExportedLinksWithoutLinks, 19 UnusedExportedPrefix(&'static str), 20 UnusedExportedLinks(&'static str), 21 } 22 23 macro_rules! expr { 24 ($expr:expr) => {{ 25 let _ = $expr; // ensure it doesn't fall out of sync with CFG definition 26 stringify!($expr) 27 }}; 28 } 29 30 const LINKS_DOCUMENTATION: &str = 31 "https://doc.rust-lang.org/cargo/reference/build-scripts.html#the-links-manifest-key"; 32 33 impl Display for Error { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result34 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 35 match self { 36 Error::NoEnv(var) => { 37 write!(f, "missing {} environment variable", var.to_string_lossy()) 38 } 39 Error::Fs(err) => err.fmt(f), 40 Error::ExportedDirNotAbsolute(path) => write!( 41 f, 42 "element of {} must be absolute path, but was: {:?}", 43 expr!(CFG.exported_header_dirs), 44 path, 45 ), 46 Error::ExportedEmptyPrefix => write!( 47 f, 48 "element of {} must not be empty string", 49 expr!(CFG.exported_header_prefixes), 50 ), 51 Error::ExportedDirsWithoutLinks => write!( 52 f, 53 "if {} is nonempty then `links` needs to be set in Cargo.toml; see {}", 54 expr!(CFG.exported_header_dirs), 55 LINKS_DOCUMENTATION, 56 ), 57 Error::ExportedPrefixesWithoutLinks => write!( 58 f, 59 "if {} is nonempty then `links` needs to be set in Cargo.toml; see {}", 60 expr!(CFG.exported_header_prefixes), 61 LINKS_DOCUMENTATION, 62 ), 63 Error::ExportedLinksWithoutLinks => write!( 64 f, 65 "if {} is nonempty then `links` needs to be set in Cargo.toml; see {}", 66 expr!(CFG.exported_header_links), 67 LINKS_DOCUMENTATION, 68 ), 69 Error::UnusedExportedPrefix(unused) => write!( 70 f, 71 "unused element in {}: {:?} does not match the include prefix of any direct dependency", 72 expr!(CFG.exported_header_prefixes), 73 unused, 74 ), 75 Error::UnusedExportedLinks(unused) => write!( 76 f, 77 "unused element in {}: {:?} does not match the `links` attribute any direct dependency", 78 expr!(CFG.exported_header_links), 79 unused, 80 ), 81 } 82 } 83 } 84 85 impl StdError for Error { source(&self) -> Option<&(dyn StdError + 'static)>86 fn source(&self) -> Option<&(dyn StdError + 'static)> { 87 match self { 88 Error::Fs(err) => err.source(), 89 _ => None, 90 } 91 } 92 } 93 94 impl From<fs::Error> for Error { from(err: fs::Error) -> Self95 fn from(err: fs::Error) -> Self { 96 Error::Fs(err) 97 } 98 } 99