Skip to content

Commit 1ddd4e6

Browse files
committedOct 11, 2021
Auto merge of #89752 - matthiaskrgr:rollup-v4fgmwg, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - #89579 (Add regression test for issue 80108) - #89632 (Fix docblock code display on mobile) - #89691 (Move `DebuggerCommands` and `check_debugger_output` to a separate module) - #89707 (Apply clippy suggestions for std) - #89722 (Fix spelling: Cannonical -> Canonical) - #89736 (Remove unused CSS rule) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
·
1.90.01.57.0
2 parents 3bf5575 + bf01a59 commit 1ddd4e6

File tree

15 files changed

+203
-151
lines changed

15 files changed

+203
-151
lines changed
 

‎compiler/rustc_middle/src/traits/select.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,14 +264,14 @@ impl EvaluationResult {
264264
/// Indicates that trait evaluation caused overflow and in which pass.
265265
#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)]
266266
pub enum OverflowError {
267-
Cannonical,
267+
Canonical,
268268
ErrorReporting,
269269
}
270270

271271
impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
272272
fn from(overflow_error: OverflowError) -> SelectionError<'tcx> {
273273
match overflow_error {
274-
OverflowError::Cannonical => SelectionError::Overflow,
274+
OverflowError::Canonical => SelectionError::Overflow,
275275
OverflowError::ErrorReporting => SelectionError::ErrorReporting,
276276
}
277277
}

‎compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,10 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
8383
) -> EvaluationResult {
8484
match self.evaluate_obligation(obligation) {
8585
Ok(result) => result,
86-
Err(OverflowError::Cannonical) => {
86+
Err(OverflowError::Canonical) => {
8787
let mut selcx = SelectionContext::with_query_mode(&self, TraitQueryMode::Standard);
8888
selcx.evaluate_root_obligation(obligation).unwrap_or_else(|r| match r {
89-
OverflowError::Cannonical => {
89+
OverflowError::Canonical => {
9090
span_bug!(
9191
obligation.cause.span,
9292
"Overflow should be caught earlier in standard query mode: {:?}, {:?}",

‎compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
161161
Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval }))
162162
}
163163
Ok(_) => Ok(None),
164-
Err(OverflowError::Cannonical) => Err(Overflow),
164+
Err(OverflowError::Canonical) => Err(Overflow),
165165
Err(OverflowError::ErrorReporting) => Err(ErrorReporting),
166166
})
167167
.flat_map(Result::transpose)

‎compiler/rustc_trait_selection/src/traits/select/mod.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -900,7 +900,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
900900
match self.candidate_from_obligation(stack) {
901901
Ok(Some(c)) => self.evaluate_candidate(stack, &c),
902902
Ok(None) => Ok(EvaluatedToAmbig),
903-
Err(Overflow) => Err(OverflowError::Cannonical),
903+
Err(Overflow) => Err(OverflowError::Canonical),
904904
Err(ErrorReporting) => Err(OverflowError::ErrorReporting),
905905
Err(..) => Ok(EvaluatedToErr),
906906
}
@@ -1064,7 +1064,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10641064
self.infcx.report_overflow_error(error_obligation, true);
10651065
}
10661066
TraitQueryMode::Canonical => {
1067-
return Err(OverflowError::Cannonical);
1067+
return Err(OverflowError::Canonical);
10681068
}
10691069
}
10701070
}

‎library/std/src/io/buffered/bufreader.rs‎

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -242,14 +242,13 @@ impl<R: Seek> BufReader<R> {
242242
self.pos = new_pos as usize;
243243
return Ok(());
244244
}
245-
} else {
246-
if let Some(new_pos) = pos.checked_add(offset as u64) {
247-
if new_pos <= self.cap as u64 {
248-
self.pos = new_pos as usize;
249-
return Ok(());
250-
}
245+
} else if let Some(new_pos) = pos.checked_add(offset as u64) {
246+
if new_pos <= self.cap as u64 {
247+
self.pos = new_pos as usize;
248+
return Ok(());
251249
}
252250
}
251+
253252
self.seek(SeekFrom::Current(offset)).map(drop)
254253
}
255254
}

‎library/std/src/sys/windows/fs.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@ impl IntoInner<Handle> for File {
558558

559559
impl FromInner<Handle> for File {
560560
fn from_inner(handle: Handle) -> File {
561-
File { handle: handle }
561+
File { handle }
562562
}
563563
}
564564

@@ -672,7 +672,7 @@ impl FilePermissions {
672672

673673
impl FileType {
674674
fn new(attrs: c::DWORD, reparse_tag: c::DWORD) -> FileType {
675-
FileType { attributes: attrs, reparse_tag: reparse_tag }
675+
FileType { attributes: attrs, reparse_tag }
676676
}
677677
pub fn is_dir(&self) -> bool {
678678
!self.is_symlink() && self.is_directory()

‎library/std/src/sys/windows/stack_overflow.rs‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ impl Handler {
99
pub unsafe fn new() -> Handler {
1010
// This API isn't available on XP, so don't panic in that case and just
1111
// pray it works out ok.
12-
if c::SetThreadStackGuarantee(&mut 0x5000) == 0 {
13-
if c::GetLastError() as u32 != c::ERROR_CALL_NOT_IMPLEMENTED as u32 {
14-
panic!("failed to reserve stack space for exception handling");
15-
}
12+
if c::SetThreadStackGuarantee(&mut 0x5000) == 0
13+
&& c::GetLastError() as u32 != c::ERROR_CALL_NOT_IMPLEMENTED as u32
14+
{
15+
panic!("failed to reserve stack space for exception handling");
1616
}
1717
Handler
1818
}

‎library/std/src/sys_common/backtrace.rs‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,8 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
9393
if stop {
9494
return false;
9595
}
96-
if !hit {
97-
if start {
98-
res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
99-
}
96+
if !hit && start {
97+
res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
10098
}
10199

102100
idx += 1;

‎src/librustdoc/clean/blanket_impl.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
7878
);
7979
match infcx.evaluate_obligation(&obligation) {
8080
Ok(eval_result) if eval_result.may_apply() => {}
81-
Err(traits::OverflowError::Cannonical) => {}
81+
Err(traits::OverflowError::Canonical) => {}
8282
Err(traits::OverflowError::ErrorReporting) => {}
8383
_ => {
8484
return false;

‎src/librustdoc/html/static/css/rustdoc.css‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -773,8 +773,6 @@ h2.small-section-header > .anchor {
773773

774774
.item-table {
775775
display: table-row;
776-
/* align content left */
777-
justify-items: start;
778776
}
779777
.item-row {
780778
display: table-row;
@@ -1969,4 +1967,8 @@ details.undocumented[open] > summary::before {
19691967
.docblock {
19701968
margin-left: 12px;
19711969
}
1970+
1971+
.docblock code {
1972+
overflow-wrap: anywhere;
1973+
}
19721974
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// If we have a long `<code>`, we need to ensure that it'll be fully displayed on mobile, meaning
2+
// that it'll be on two lines.
3+
emulate: "iPhone 8" // it has the following size: (375, 667)
4+
goto: file://|DOC_PATH|/test_docs/long_code_block/index.html
5+
// We now check that the block is on two lines:
6+
show-text: true // We need to enable text draw to be able to have the "real" size
7+
// Little explanations for this test: if the text wasn't displayed on two lines, it would take
8+
// around 20px (which is the font size).
9+
assert-property: (".docblock p > code", {"offsetHeight": "42"})

‎src/test/rustdoc-gui/src/test_docs/lib.rs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,6 @@ pub type SomeType = u32;
120120
pub mod huge_amount_of_consts {
121121
include!(concat!(env!("OUT_DIR"), "/huge_amount_of_consts.rs"));
122122
}
123+
124+
/// Very long code text `hereIgoWithLongTextBecauseWhyNotAndWhyWouldntI`.
125+
pub mod long_code_block {}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// only-wasm32
2+
// compile-flags: --crate-type=lib -Copt-level=2
3+
// build-pass
4+
#![feature(repr_simd)]
5+
6+
// Regression test for #80108
7+
8+
#[repr(simd)]
9+
pub struct Vector([i32; 4]);
10+
11+
impl Vector {
12+
pub const fn to_array(self) -> [i32; 4] {
13+
self.0
14+
}
15+
}

‎src/tools/compiletest/src/runtest.rs‎

Lines changed: 36 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ use tracing::*;
3838
use crate::extract_gdb_version;
3939
use crate::is_android_gdb_target;
4040

41+
mod debugger;
42+
use debugger::{check_debugger_output, DebuggerCommands};
43+
4144
#[cfg(test)]
4245
mod tests;
4346

@@ -200,12 +203,6 @@ struct TestCx<'test> {
200203
revision: Option<&'test str>,
201204
}
202205

203-
struct DebuggerCommands {
204-
commands: Vec<String>,
205-
check_lines: Vec<String>,
206-
breakpoint_lines: Vec<usize>,
207-
}
208-
209206
enum ReadFrom {
210207
Path,
211208
Stdin(String),
@@ -235,10 +232,8 @@ impl<'test> TestCx<'test> {
235232
/// Code executed for each revision in turn (or, if there are no
236233
/// revisions, exactly once, with revision == None).
237234
fn run_revision(&self) {
238-
if self.props.should_ice {
239-
if self.config.mode != Incremental {
240-
self.fatal("cannot use should-ice in a test that is not cfail");
241-
}
235+
if self.props.should_ice && self.config.mode != Incremental {
236+
self.fatal("cannot use should-ice in a test that is not cfail");
242237
}
243238
match self.config.mode {
244239
RunPassValgrind => self.run_valgrind_test(),
@@ -674,7 +669,10 @@ impl<'test> TestCx<'test> {
674669

675670
// Parse debugger commands etc from test files
676671
let DebuggerCommands { commands, check_lines, breakpoint_lines, .. } =
677-
self.parse_debugger_commands(prefixes);
672+
match DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) {
673+
Ok(cmds) => cmds,
674+
Err(e) => self.fatal(&e),
675+
};
678676

679677
// https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands
680678
let mut script_str = String::with_capacity(2048);
@@ -726,7 +724,9 @@ impl<'test> TestCx<'test> {
726724
self.fatal_proc_rec("Error while running CDB", &debugger_run_result);
727725
}
728726

729-
self.check_debugger_output(&debugger_run_result, &check_lines);
727+
if let Err(e) = check_debugger_output(&debugger_run_result, &check_lines) {
728+
self.fatal_proc_rec(&e, &debugger_run_result);
729+
}
730730
}
731731

732732
fn run_debuginfo_gdb_test(&self) {
@@ -757,7 +757,10 @@ impl<'test> TestCx<'test> {
757757
};
758758

759759
let DebuggerCommands { commands, check_lines, breakpoint_lines } =
760-
self.parse_debugger_commands(prefixes);
760+
match DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) {
761+
Ok(cmds) => cmds,
762+
Err(e) => self.fatal(&e),
763+
};
761764
let mut cmds = commands.join("\n");
762765

763766
// compile test file (it should have 'compile-flags:-g' in the header)
@@ -960,7 +963,9 @@ impl<'test> TestCx<'test> {
960963
self.fatal_proc_rec("gdb failed to execute", &debugger_run_result);
961964
}
962965

963-
self.check_debugger_output(&debugger_run_result, &check_lines);
966+
if let Err(e) = check_debugger_output(&debugger_run_result, &check_lines) {
967+
self.fatal_proc_rec(&e, &debugger_run_result);
968+
}
964969
}
965970

966971
fn run_debuginfo_lldb_test(&self) {
@@ -1018,7 +1023,10 @@ impl<'test> TestCx<'test> {
10181023

10191024
// Parse debugger commands etc from test files
10201025
let DebuggerCommands { commands, check_lines, breakpoint_lines, .. } =
1021-
self.parse_debugger_commands(prefixes);
1026+
match DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) {
1027+
Ok(cmds) => cmds,
1028+
Err(e) => self.fatal(&e),
1029+
};
10221030

10231031
// Write debugger script:
10241032
// We don't want to hang when calling `quit` while the process is still running
@@ -1094,7 +1102,9 @@ impl<'test> TestCx<'test> {
10941102
self.fatal_proc_rec("Error while running LLDB", &debugger_run_result);
10951103
}
10961104

1097-
self.check_debugger_output(&debugger_run_result, &check_lines);
1105+
if let Err(e) = check_debugger_output(&debugger_run_result, &check_lines) {
1106+
self.fatal_proc_rec(&e, &debugger_run_result);
1107+
}
10981108
}
10991109

11001110
fn run_lldb(
@@ -1131,45 +1141,6 @@ impl<'test> TestCx<'test> {
11311141
ProcRes { status, stdout: out, stderr: err, cmdline: format!("{:?}", cmd) }
11321142
}
11331143

1134-
fn parse_debugger_commands(&self, debugger_prefixes: &[&str]) -> DebuggerCommands {
1135-
let directives = debugger_prefixes
1136-
.iter()
1137-
.map(|prefix| (format!("{}-command", prefix), format!("{}-check", prefix)))
1138-
.collect::<Vec<_>>();
1139-
1140-
let mut breakpoint_lines = vec![];
1141-
let mut commands = vec![];
1142-
let mut check_lines = vec![];
1143-
let mut counter = 1;
1144-
let reader = BufReader::new(File::open(&self.testpaths.file).unwrap());
1145-
for line in reader.lines() {
1146-
match line {
1147-
Ok(line) => {
1148-
let line =
1149-
if line.starts_with("//") { line[2..].trim_start() } else { line.as_str() };
1150-
1151-
if line.contains("#break") {
1152-
breakpoint_lines.push(counter);
1153-
}
1154-
1155-
for &(ref command_directive, ref check_directive) in &directives {
1156-
self.config
1157-
.parse_name_value_directive(&line, command_directive)
1158-
.map(|cmd| commands.push(cmd));
1159-
1160-
self.config
1161-
.parse_name_value_directive(&line, check_directive)
1162-
.map(|cmd| check_lines.push(cmd));
1163-
}
1164-
}
1165-
Err(e) => self.fatal(&format!("Error while parsing debugger commands: {}", e)),
1166-
}
1167-
counter += 1;
1168-
}
1169-
1170-
DebuggerCommands { commands, check_lines, breakpoint_lines }
1171-
}
1172-
11731144
fn cleanup_debug_info_options(&self, options: &Option<String>) -> Option<String> {
11741145
if options.is_none() {
11751146
return None;
@@ -1216,66 +1187,6 @@ impl<'test> TestCx<'test> {
12161187
}
12171188
}
12181189

1219-
fn check_debugger_output(&self, debugger_run_result: &ProcRes, check_lines: &[String]) {
1220-
let num_check_lines = check_lines.len();
1221-
1222-
let mut check_line_index = 0;
1223-
for line in debugger_run_result.stdout.lines() {
1224-
if check_line_index >= num_check_lines {
1225-
break;
1226-
}
1227-
1228-
if check_single_line(line, &(check_lines[check_line_index])[..]) {
1229-
check_line_index += 1;
1230-
}
1231-
}
1232-
if check_line_index != num_check_lines && num_check_lines > 0 {
1233-
self.fatal_proc_rec(
1234-
&format!("line not found in debugger output: {}", check_lines[check_line_index]),
1235-
debugger_run_result,
1236-
);
1237-
}
1238-
1239-
fn check_single_line(line: &str, check_line: &str) -> bool {
1240-
// Allow check lines to leave parts unspecified (e.g., uninitialized
1241-
// bits in the wrong case of an enum) with the notation "[...]".
1242-
let line = line.trim();
1243-
let check_line = check_line.trim();
1244-
let can_start_anywhere = check_line.starts_with("[...]");
1245-
let can_end_anywhere = check_line.ends_with("[...]");
1246-
1247-
let check_fragments: Vec<&str> =
1248-
check_line.split("[...]").filter(|frag| !frag.is_empty()).collect();
1249-
if check_fragments.is_empty() {
1250-
return true;
1251-
}
1252-
1253-
let (mut rest, first_fragment) = if can_start_anywhere {
1254-
match line.find(check_fragments[0]) {
1255-
Some(pos) => (&line[pos + check_fragments[0].len()..], 1),
1256-
None => return false,
1257-
}
1258-
} else {
1259-
(line, 0)
1260-
};
1261-
1262-
for current_fragment in &check_fragments[first_fragment..] {
1263-
match rest.find(current_fragment) {
1264-
Some(pos) => {
1265-
rest = &rest[pos + current_fragment.len()..];
1266-
}
1267-
None => return false,
1268-
}
1269-
}
1270-
1271-
if !can_end_anywhere && !rest.is_empty() {
1272-
return false;
1273-
}
1274-
1275-
true
1276-
}
1277-
}
1278-
12791190
fn check_error_patterns(
12801191
&self,
12811192
output_to_check: &str,
@@ -2154,9 +2065,9 @@ impl<'test> TestCx<'test> {
21542065

21552066
fn maybe_dump_to_stdout(&self, out: &str, err: &str) {
21562067
if self.config.verbose {
2157-
println!("------{}------------------------------", "stdout");
2068+
println!("------stdout------------------------------");
21582069
println!("{}", out);
2159-
println!("------{}------------------------------", "stderr");
2070+
println!("------stderr------------------------------");
21602071
println!("{}", err);
21612072
println!("------------------------------------------");
21622073
}
@@ -3249,11 +3160,10 @@ impl<'test> TestCx<'test> {
32493160
if !proc_res.status.success() {
32503161
self.fatal_proc_rec("test run failed!", &proc_res);
32513162
}
3252-
} else {
3253-
if proc_res.status.success() {
3254-
self.fatal_proc_rec("test run succeeded!", &proc_res);
3255-
}
3163+
} else if proc_res.status.success() {
3164+
self.fatal_proc_rec("test run succeeded!", &proc_res);
32563165
}
3166+
32573167
if !self.props.error_patterns.is_empty() {
32583168
// "// error-pattern" comments
32593169
self.check_error_patterns(&proc_res.stderr, &proc_res, pm);
@@ -3300,10 +3210,11 @@ impl<'test> TestCx<'test> {
33003210
if !res.status.success() {
33013211
self.fatal_proc_rec("failed to compile fixed code", &res);
33023212
}
3303-
if !res.stderr.is_empty() && !self.props.rustfix_only_machine_applicable {
3304-
if !json::rustfix_diagnostics_only(&res.stderr).is_empty() {
3305-
self.fatal_proc_rec("fixed code is still producing diagnostics", &res);
3306-
}
3213+
if !res.stderr.is_empty()
3214+
&& !self.props.rustfix_only_machine_applicable
3215+
&& !json::rustfix_diagnostics_only(&res.stderr).is_empty()
3216+
{
3217+
self.fatal_proc_rec("fixed code is still producing diagnostics", &res);
33073218
}
33083219
}
33093220
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
use crate::common::Config;
2+
use crate::runtest::ProcRes;
3+
4+
use std::fs::File;
5+
use std::io::{BufRead, BufReader};
6+
use std::path::Path;
7+
8+
pub(super) struct DebuggerCommands {
9+
pub commands: Vec<String>,
10+
pub check_lines: Vec<String>,
11+
pub breakpoint_lines: Vec<usize>,
12+
}
13+
14+
impl DebuggerCommands {
15+
pub(super) fn parse_from(
16+
file: &Path,
17+
config: &Config,
18+
debugger_prefixes: &[&str],
19+
) -> Result<Self, String> {
20+
let directives = debugger_prefixes
21+
.iter()
22+
.map(|prefix| (format!("{}-command", prefix), format!("{}-check", prefix)))
23+
.collect::<Vec<_>>();
24+
25+
let mut breakpoint_lines = vec![];
26+
let mut commands = vec![];
27+
let mut check_lines = vec![];
28+
let mut counter = 1;
29+
let reader = BufReader::new(File::open(file).unwrap());
30+
for line in reader.lines() {
31+
match line {
32+
Ok(line) => {
33+
let line =
34+
if line.starts_with("//") { line[2..].trim_start() } else { line.as_str() };
35+
36+
if line.contains("#break") {
37+
breakpoint_lines.push(counter);
38+
}
39+
40+
for &(ref command_directive, ref check_directive) in &directives {
41+
config
42+
.parse_name_value_directive(&line, command_directive)
43+
.map(|cmd| commands.push(cmd));
44+
45+
config
46+
.parse_name_value_directive(&line, check_directive)
47+
.map(|cmd| check_lines.push(cmd));
48+
}
49+
}
50+
Err(e) => return Err(format!("Error while parsing debugger commands: {}", e)),
51+
}
52+
counter += 1;
53+
}
54+
55+
Ok(Self { commands, check_lines, breakpoint_lines })
56+
}
57+
}
58+
59+
pub(super) fn check_debugger_output(
60+
debugger_run_result: &ProcRes,
61+
check_lines: &[String],
62+
) -> Result<(), String> {
63+
let num_check_lines = check_lines.len();
64+
65+
let mut check_line_index = 0;
66+
for line in debugger_run_result.stdout.lines() {
67+
if check_line_index >= num_check_lines {
68+
break;
69+
}
70+
71+
if check_single_line(line, &(check_lines[check_line_index])[..]) {
72+
check_line_index += 1;
73+
}
74+
}
75+
if check_line_index != num_check_lines && num_check_lines > 0 {
76+
Err(format!("line not found in debugger output: {}", check_lines[check_line_index]))
77+
} else {
78+
Ok(())
79+
}
80+
}
81+
82+
fn check_single_line(line: &str, check_line: &str) -> bool {
83+
// Allow check lines to leave parts unspecified (e.g., uninitialized
84+
// bits in the wrong case of an enum) with the notation "[...]".
85+
let line = line.trim();
86+
let check_line = check_line.trim();
87+
let can_start_anywhere = check_line.starts_with("[...]");
88+
let can_end_anywhere = check_line.ends_with("[...]");
89+
90+
let check_fragments: Vec<&str> =
91+
check_line.split("[...]").filter(|frag| !frag.is_empty()).collect();
92+
if check_fragments.is_empty() {
93+
return true;
94+
}
95+
96+
let (mut rest, first_fragment) = if can_start_anywhere {
97+
match line.find(check_fragments[0]) {
98+
Some(pos) => (&line[pos + check_fragments[0].len()..], 1),
99+
None => return false,
100+
}
101+
} else {
102+
(line, 0)
103+
};
104+
105+
for current_fragment in &check_fragments[first_fragment..] {
106+
match rest.find(current_fragment) {
107+
Some(pos) => {
108+
rest = &rest[pos + current_fragment.len()..];
109+
}
110+
None => return false,
111+
}
112+
}
113+
114+
if !can_end_anywhere && !rest.is_empty() { false } else { true }
115+
}

0 commit comments

Comments
 (0)
Please sign in to comment.