Repository: rust-lang/rustfmt (rust)

Issue:
Panic with `wrap_comments` and non-ascii character at comment wrap boundary
There is a piece of code in my project like:

```rust
fn main() {
    if xxx {
        let xxx = xxx
            .into_iter()
            .filter(|(xxx, xxx)| {
                if let Some(x) = Some(1) {
                    // xxxxxxxxxxxxxxxxxx, xxxxxxxxxxxx, xxxxxxxxxxxxxxxxxxxx xxx xxxxxxx, xxxxx xxx
                    // xxxxxxxxxx. xxxxxxxxxxxxxxxx，xxxxxxxxxxxxxxxxx xxx xxxxxxx
                    // 是sdfadsdfxxxxxxxxx，sdfaxxxxxx_xxxxx_masdfaonxxx，
                    if false {
                        return true;
                    }
                }
                false
            })
            .collect();
    }
}
```

When I execute `cargo fmt`, I got an error:

```
thread 'main' panicked at 'index out of bounds: the len is 48 but the index is 18446744073709551615', src/tools/rustfmt/src/string.rs:285:27
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```

The `rustfmt.toml` is the following:

```
wrap_comments = true
```

I can't understand why a few lines of comments can make fmt crash...

Pull request description:
Handle non-ascii character at boundary
Close #5023 

Patch:
diff --git a/src/string.rs b/src/string.rs
index 64ae1567..b65aa5b3 100644
--- a/src/string.rs
+++ b/src/string.rs
@@ -278,6 +278,9 @@ fn break_string(max_width: usize, trim_end: bool, line_end: &str, input: &[&str]
         }
         cur_index
     };
+    if max_width_index_in_input == 0 {
+        return SnippetState::EndOfInput(input.concat());
+    }
 
     // Find the position in input for breaking the string
     if line_end.is_empty()
@@ -301,7 +304,7 @@ fn break_string(max_width: usize, trim_end: bool, line_end: &str, input: &[&str]
         return if trim_end {
             SnippetState::LineEnd(input[..=url_index_end].concat(), index_plus_ws + 1)
         } else {
-            return SnippetState::LineEnd(input[..=index_plus_ws].concat(), index_plus_ws + 1);
+            SnippetState::LineEnd(input[..=index_plus_ws].concat(), index_plus_ws + 1)
         };
     }
 


Test patch:
diff --git a/tests/source/issue-5023.rs b/tests/source/issue-5023.rs
new file mode 100644
index 00000000..ae1c723e
--- /dev/null
+++ b/tests/source/issue-5023.rs
@@ -0,0 +1,22 @@
+// rustfmt-wrap_comments: true
+
+/// A comment to test special unicode characters on boundaries
+/// 是，是，是，是，是，是，是，是，是，是，是，是  it should break right here this goes to the next line
+fn main() {
+    if xxx {
+        let xxx = xxx
+            .into_iter()
+            .filter(|(xxx, xxx)| {
+                if let Some(x) = Some(1) {
+                    // xxxxxxxxxxxxxxxxxx, xxxxxxxxxxxx, xxxxxxxxxxxxxxxxxxxx xxx xxxxxxx, xxxxx xxx
+                    // xxxxxxxxxx. xxxxxxxxxxxxxxxx，xxxxxxxxxxxxxxxxx xxx xxxxxxx
+                    // 是sdfadsdfxxxxxxxxx，sdfaxxxxxx_xxxxx_masdfaonxxx，
+                    if false {
+                        return true;
+                    }
+                }
+                false
+            })
+            .collect();
+    }
+}
diff --git a/tests/target/issue-5023.rs b/tests/target/issue-5023.rs
new file mode 100644
index 00000000..4e84c7d9
--- /dev/null
+++ b/tests/target/issue-5023.rs
@@ -0,0 +1,23 @@
+// rustfmt-wrap_comments: true
+
+/// A comment to test special unicode characters on boundaries
+/// 是，是，是，是，是，是，是，是，是，是，是，是  it should break right here
+/// this goes to the next line
+fn main() {
+    if xxx {
+        let xxx = xxx
+            .into_iter()
+            .filter(|(xxx, xxx)| {
+                if let Some(x) = Some(1) {
+                    // xxxxxxxxxxxxxxxxxx, xxxxxxxxxxxx, xxxxxxxxxxxxxxxxxxxx xxx xxxxxxx, xxxxx xxx
+                    // xxxxxxxxxx. xxxxxxxxxxxxxxxx，xxxxxxxxxxxxxxxxx xxx xxxxxxx
+                    // 是sdfadsdfxxxxxxxxx，sdfaxxxxxx_xxxxx_masdfaonxxx，
+                    if false {
+                        return true;
+                    }
+                }
+                false
+            })
+            .collect();
+    }
+}