Skip to content

Commit 941a83e

Browse files
committed
refactor(embedded): Pull in parser from rust-lang/rust#137193
1 parent a6dc70e commit 941a83e

File tree

1 file changed

+46
-35
lines changed

1 file changed

+46
-35
lines changed

src/cargo/util/toml/embedded.rs

Lines changed: 46 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -146,59 +146,70 @@ impl<'s> ScriptSource<'s> {
146146
source.content = content;
147147
}
148148

149-
const FENCE_CHAR: char = '-';
150-
151149
let mut rest = source.content;
152-
while !rest.is_empty() {
153-
let without_spaces = rest.trim_start_matches([' ', '\t']);
154-
let without_nl = without_spaces.trim_start_matches(['\r', '\n']);
155-
if without_nl == rest {
156-
// nothing trimmed
157-
break;
158-
} else if without_nl == without_spaces {
159-
// frontmatter must come after a newline
150+
151+
// Whitespace may precede a frontmatter but must end with a newline
152+
const WHITESPACE: [char; 4] = [' ', '\t', '\r', '\n'];
153+
let trimmed = rest.trim_start_matches(WHITESPACE);
154+
if trimmed.len() != rest.len() {
155+
let trimmed_len = rest.len() - trimmed.len();
156+
let last_trimmed_index = trimmed_len - 1;
157+
if rest.as_bytes()[last_trimmed_index] != b'\n' {
158+
// either not a frontmatter or invalid opening
160159
return Ok(source);
161160
}
162-
rest = without_nl;
163161
}
164-
let fence_end = rest
162+
rest = trimmed;
163+
164+
// Opens with a line that starts with 3 or more `-` followed by an optional identifier
165+
const FENCE_CHAR: char = '-';
166+
let fence_length = rest
165167
.char_indices()
166168
.find_map(|(i, c)| (c != FENCE_CHAR).then_some(i))
167-
.unwrap_or(source.content.len());
168-
let (fence_pattern, rest) = match fence_end {
169+
.unwrap_or(rest.len());
170+
match fence_length {
169171
0 => {
170172
return Ok(source);
171173
}
172174
1 | 2 => {
175+
// either not a frontmatter or invalid frontmatter opening
173176
anyhow::bail!(
174-
"found {fence_end} `{FENCE_CHAR}` in rust frontmatter, expected at least 3"
177+
"found {fence_length} `{FENCE_CHAR}` in rust frontmatter, expected at least 3"
175178
)
176179
}
177-
_ => rest.split_at(fence_end),
180+
_ => {}
181+
}
182+
let (fence_pattern, rest) = rest.split_at(fence_length);
183+
let Some(info_end_index) = rest.find('\n') else {
184+
anyhow::bail!("no closing `{fence_pattern}` found for frontmatter");
178185
};
179-
let nl_fence_pattern = format!("\n{fence_pattern}");
180-
let (info, content) = rest.split_once("\n").unwrap_or((rest, ""));
181-
let info = info.trim();
186+
let (info, rest) = rest.split_at(info_end_index);
187+
let info = info.trim_matches(WHITESPACE);
182188
if !info.is_empty() {
183189
source.info = Some(info);
184190
}
185-
source.content = content;
191+
let rest = rest
192+
.strip_prefix('\n')
193+
.expect("earlier `found` + `split_at` left us here");
186194

187-
let Some(frontmatter_nl) = source.content.find(&nl_fence_pattern) else {
195+
// Ends with a line that starts with a matching number of `-` only followed by whitespace
196+
let nl_fence_pattern = format!("\n{fence_pattern}");
197+
let Some(frontmatter_nl) = rest.find(&nl_fence_pattern) else {
188198
anyhow::bail!("no closing `{fence_pattern}` found for frontmatter");
189199
};
190-
source.frontmatter = Some(&source.content[..frontmatter_nl + 1]);
191-
source.content = &source.content[frontmatter_nl + nl_fence_pattern.len()..];
192-
193-
let (line, content) = source
194-
.content
195-
.split_once("\n")
196-
.unwrap_or((source.content, ""));
197-
let line = line.trim();
198-
if !line.is_empty() {
199-
anyhow::bail!("unexpected trailing content on closing fence: `{line}`");
200+
let frontmatter = &rest[..frontmatter_nl + 1];
201+
let rest = &rest[frontmatter_nl + nl_fence_pattern.len()..];
202+
source.frontmatter = Some(frontmatter);
203+
204+
let (after_closing_fence, rest) = rest.split_once("\n").unwrap_or((rest, ""));
205+
let after_closing_fence = after_closing_fence.trim_matches(WHITESPACE);
206+
if !after_closing_fence.is_empty() {
207+
// extra characters beyond the original fence pattern, even if they are extra `-`
208+
anyhow::bail!("trailing characters found after frontmatter close");
200209
}
201-
source.content = content;
210+
211+
let frontmatter_len = input.len() - rest.len();
212+
source.content = &input[frontmatter_len..];
202213

203214
Ok(source)
204215
}
@@ -534,7 +545,7 @@ content: "\n// infostrings can only be a single identifier.\n\nfn main() {}\n"
534545
fn main() {}
535546
"#,
536547
),
537-
str!["unexpected trailing content on closing fence: `-`"],
548+
str!["trailing characters found after frontmatter close"],
538549
);
539550
}
540551

@@ -973,7 +984,7 @@ content: "\nfn main() {}\n"
973984
fn main() {}
974985
"#,
975986
),
976-
str!["unexpected trailing content on closing fence: `--`"],
987+
str!["trailing characters found after frontmatter close"],
977988
);
978989
}
979990

@@ -1010,7 +1021,7 @@ time="0.1.25"
10101021
fn main() {}
10111022
"#,
10121023
),
1013-
str!["unexpected trailing content on closing fence: `-`"],
1024+
str!["trailing characters found after frontmatter close"],
10141025
);
10151026
}
10161027

0 commit comments

Comments
 (0)