1use {
5 super::token,
6 core::fmt::Debug,
7 either::Either,
8 rustidy_ast_util::{Identifier, Punctuated, punct},
9 rustidy_format::{Format, Formattable, WhitespaceFormat},
10 rustidy_parse::Parse,
11 rustidy_print::Print,
12 rustidy_util::Whitespace,
13 std::borrow::Cow,
14};
15
16#[derive(PartialEq, Eq, Clone, Debug)]
18#[derive(serde::Serialize, serde::Deserialize)]
19#[derive(Parse, Formattable, Format, Print)]
20#[parse(name = "a simple path")]
21pub struct SimplePath {
22 pub prefix: Option<token::PathSep>,
23 #[format(prefix_ws(expr = Whitespace::REMOVE, if_ = self.prefix.is_some()))]
24 #[format(args = punct::fmt(Whitespace::REMOVE, Whitespace::REMOVE))]
25 pub segments: Punctuated<SimplePathSegment, token::PathSep>,
26}
27
28impl SimplePath {
29 #[must_use]
31 pub fn as_str(&self) -> Cow<'_, str> {
32 if self.prefix.is_none() && self.segments.rest.is_empty() {
34 return self.segments.first.as_str();
35 }
36
37 let mut output = String::new();
39 if self.prefix.is_some() {
40 output.push_str("::");
41 }
42 for segment in self.segments.iter() {
43 match segment {
44 Either::Left(segment) => output.push_str(&segment.as_str()),
45 Either::Right(_) => output.push_str("::"),
46 }
47 }
48
49 output.into()
50 }
51
52 #[must_use]
54 pub fn starts_with(&self, segment: &str) -> bool {
55 self.segments.first.is_str(segment)
57 }
58
59 #[must_use]
61 pub fn is_str(&self, path: &str) -> bool {
62 let (path, has_prefix) = match path.strip_prefix("::") {
64 Some(path) => (path, true),
65 None => (path, false),
66 };
67 if self.prefix.is_some() != has_prefix {
68 return false;
69 }
70
71 let mut lhs_segments = self.segments.values();
73 let mut rhs_segments = path.split("::");
74 loop {
75 match (lhs_segments.next(), rhs_segments.next()) {
76 (None, None) => break,
77 (None, Some(_)) | (Some(_), None) => return false,
78 (Some(lhs), Some(rhs)) => if !lhs.is_str(rhs) {
79 return false;
80 },
81 }
82 }
83
84 true
85 }
86}
87
88#[derive(PartialEq, Eq, Clone, Debug)]
90#[derive(strum::EnumTryAs)]
91#[derive(serde::Serialize, serde::Deserialize)]
92#[derive(Parse, Formattable, Format, Print)]
93pub enum SimplePathSegment {
94 Super(token::Super),
95 SelfLower(token::SelfLower),
96 Crate(token::Crate),
97 DollarCrate(token::DollarCrate),
98 Ident(Identifier),
99}
100
101impl SimplePathSegment {
102 #[must_use]
104 pub fn as_str(&self) -> Cow<'_, str> {
105 match self {
106 Self::Super(_) => "super".into(),
107 Self::SelfLower(_) => "self".into(),
108 Self::Crate(_) => "crate".into(),
109 Self::DollarCrate(_) => "$crate".into(),
110 Self::Ident(ident) => ident.as_str(),
111 }
112 }
113
114 #[must_use]
116 pub fn is_str(&self, segment: &str) -> bool {
117 match self {
118 Self::Super(_) => segment == "super",
119 Self::SelfLower(_) => segment == "self",
120 Self::Crate(_) => segment == "crate",
121 Self::DollarCrate(_) => segment == "$crate",
122 Self::Ident(ident) => ident.is_str(segment),
123 }
124 }
125}