1use std::fmt;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
4pub enum PathRejection {
5 Empty,
6 #[allow(dead_code)]
7 TooLong,
8 UnsupportedUriForm,
9 MalformedPercentEncoding,
10 InvalidUtf8,
11 NulByte,
12 #[allow(dead_code)]
13 AbsolutePath,
14 ParentComponent,
15 CurrentComponent,
16 SeparatorAmbiguity,
17 DotfileDenied,
18 WindowsPrefixDenied,
19 WindowsReservedNameDenied,
20 WindowsAlternateStreamDenied,
21 SymlinkDenied,
22 RootEscapeDenied,
23}
24
25impl fmt::Display for PathRejection {
26 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 match self {
28 PathRejection::Empty => write!(f, "empty path"),
29 PathRejection::TooLong => write!(f, "path too long"),
30 PathRejection::UnsupportedUriForm => write!(f, "unsupported URI form"),
31 PathRejection::MalformedPercentEncoding => {
32 write!(f, "malformed percent encoding")
33 }
34 PathRejection::InvalidUtf8 => write!(f, "invalid UTF-8"),
35 PathRejection::NulByte => write!(f, "NUL byte in path"),
36 PathRejection::AbsolutePath => write!(f, "absolute path"),
37 PathRejection::ParentComponent => write!(f, "parent component (..)"),
38 PathRejection::CurrentComponent => write!(f, "current component (.)"),
39 PathRejection::SeparatorAmbiguity => write!(f, "separator ambiguity"),
40 PathRejection::DotfileDenied => write!(f, "dotfile denied"),
41 PathRejection::WindowsPrefixDenied => write!(f, "Windows prefix denied"),
42 PathRejection::WindowsReservedNameDenied => {
43 write!(f, "Windows reserved name denied")
44 }
45 PathRejection::WindowsAlternateStreamDenied => {
46 write!(f, "Windows alternate stream denied")
47 }
48 PathRejection::SymlinkDenied => write!(f, "symlink denied by policy"),
49 PathRejection::RootEscapeDenied => write!(f, "canonical path escapes root"),
50 }
51 }
52}
53
54impl std::error::Error for PathRejection {}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59
60 #[test]
61 fn display_all_variants() {
62 let cases = &[
63 (PathRejection::Empty, "empty path"),
64 (PathRejection::TooLong, "path too long"),
65 (PathRejection::UnsupportedUriForm, "unsupported URI form"),
66 (
67 PathRejection::MalformedPercentEncoding,
68 "malformed percent encoding",
69 ),
70 (PathRejection::InvalidUtf8, "invalid UTF-8"),
71 (PathRejection::NulByte, "NUL byte in path"),
72 (PathRejection::AbsolutePath, "absolute path"),
73 (PathRejection::ParentComponent, "parent component (..)"),
74 (PathRejection::CurrentComponent, "current component (.)"),
75 (PathRejection::SeparatorAmbiguity, "separator ambiguity"),
76 (PathRejection::DotfileDenied, "dotfile denied"),
77 (PathRejection::WindowsPrefixDenied, "Windows prefix denied"),
78 (
79 PathRejection::WindowsReservedNameDenied,
80 "Windows reserved name denied",
81 ),
82 (
83 PathRejection::WindowsAlternateStreamDenied,
84 "Windows alternate stream denied",
85 ),
86 (PathRejection::SymlinkDenied, "symlink denied by policy"),
87 (
88 PathRejection::RootEscapeDenied,
89 "canonical path escapes root",
90 ),
91 ];
92 for (rejection, expected) in cases {
93 assert_eq!(rejection.to_string(), *expected);
94 }
95 }
96
97 #[test]
98 fn is_error() {
99 let err: &dyn std::error::Error = &PathRejection::Empty;
100 assert_eq!(err.to_string(), "empty path");
101 }
102}