Skip to content

Commit 63cf06e

Browse files
author
Daniel Rainer
committed
Support char iter width
Add free functions for computing the width of iterators over `char`. The semantics are the same as if the chars were combined into a string. This only works with `DoubleEndedIterator`s, because internally `rfold` is used, which is not available on arbitrary iterators. Closes #82
1 parent b10a4d5 commit 63cf06e

4 files changed

Lines changed: 46 additions & 33 deletions

File tree

scripts/unicode.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1556,16 +1556,15 @@ def lookup_fns(
15561556
}}
15571557
15581558
{cfg}#[inline]
1559-
pub fn str_width{cjk_lo}(s: &str) -> usize {{
1560-
s.chars()
1561-
.rfold(
1562-
(0, WidthInfo::DEFAULT),
1563-
|(sum, next_info), c| -> (usize, WidthInfo) {{
1564-
let (add, info) = width_in_str{cjk_lo}(c, next_info);
1565-
(sum.wrapping_add_signed(isize::from(add)), info)
1566-
}},
1567-
)
1568-
.0
1559+
pub fn str_width<S: DoubleEndedIterator<Item = char>>{cjk_lo}(s: S) -> usize {{
1560+
s.rfold(
1561+
(0, WidthInfo::DEFAULT),
1562+
|(sum, next_info), c| -> (usize, WidthInfo) {{
1563+
let (add, info) = width_in_str{cjk_lo}(c, next_info);
1564+
(sum.wrapping_add_signed(isize::from(add)), info)
1565+
}},
1566+
)
1567+
.0
15691568
}}
15701569
"""
15711570

src/lib.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,12 +248,23 @@ pub trait UnicodeWidthStr: private::Sealed {
248248
impl UnicodeWidthStr for str {
249249
#[inline]
250250
fn width(&self) -> usize {
251-
tables::str_width(self)
251+
tables::str_width(self.chars())
252252
}
253253

254254
#[cfg(feature = "cjk")]
255255
#[inline]
256256
fn width_cjk(&self) -> usize {
257-
tables::str_width_cjk(self)
257+
tables::str_width_cjk(self.chars())
258258
}
259259
}
260+
261+
/// Like [`UnicodeWidthStr::width`] but for iterators over [`char`].
262+
pub fn char_iter_width<S: DoubleEndedIterator<Item = char>>(s: S) -> usize {
263+
tables::str_width(s)
264+
}
265+
266+
/// Like [`UnicodeWidthStr::width_cjk`] but for iterators over [`char`].
267+
#[cfg(feature = "cjk")]
268+
pub fn char_iter_width_cjk<S: DoubleEndedIterator<Item = char>>(s: S) -> usize {
269+
tables::str_width_cjk(s)
270+
}

src/tables.rs

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -462,16 +462,15 @@ fn width_in_str(c: char, mut next_info: WidthInfo) -> (i8, WidthInfo) {
462462
}
463463

464464
#[inline]
465-
pub fn str_width(s: &str) -> usize {
466-
s.chars()
467-
.rfold(
468-
(0, WidthInfo::DEFAULT),
469-
|(sum, next_info), c| -> (usize, WidthInfo) {
470-
let (add, info) = width_in_str(c, next_info);
471-
(sum.wrapping_add_signed(isize::from(add)), info)
472-
},
473-
)
474-
.0
465+
pub fn str_width<S: DoubleEndedIterator<Item = char>>(s: S) -> usize {
466+
s.rfold(
467+
(0, WidthInfo::DEFAULT),
468+
|(sum, next_info), c| -> (usize, WidthInfo) {
469+
let (add, info) = width_in_str(c, next_info);
470+
(sum.wrapping_add_signed(isize::from(add)), info)
471+
},
472+
)
473+
.0
475474
}
476475

477476
/// Returns the [UAX #11](https://www.unicode.org/reports/tr11/) based width of `c` by
@@ -783,16 +782,15 @@ fn width_in_str_cjk(c: char, mut next_info: WidthInfo) -> (i8, WidthInfo) {
783782

784783
#[cfg(feature = "cjk")]
785784
#[inline]
786-
pub fn str_width_cjk(s: &str) -> usize {
787-
s.chars()
788-
.rfold(
789-
(0, WidthInfo::DEFAULT),
790-
|(sum, next_info), c| -> (usize, WidthInfo) {
791-
let (add, info) = width_in_str_cjk(c, next_info);
792-
(sum.wrapping_add_signed(isize::from(add)), info)
793-
},
794-
)
795-
.0
785+
pub fn str_width_cjk<S: DoubleEndedIterator<Item = char>>(s: S) -> usize {
786+
s.rfold(
787+
(0, WidthInfo::DEFAULT),
788+
|(sum, next_info), c| -> (usize, WidthInfo) {
789+
let (add, info) = width_in_str_cjk(c, next_info);
790+
(sum.wrapping_add_signed(isize::from(add)), info)
791+
},
792+
)
793+
.0
796794
}
797795

798796
/// Whether this character is a zero-width character with

tests/tests.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use std::{
1313
io::{BufRead, BufReader},
1414
};
1515

16-
use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
16+
use unicode_width::{char_iter_width, UnicodeWidthChar, UnicodeWidthStr};
1717

1818
macro_rules! assert_width {
1919
($s:expr, $nocjk:expr, $cjk:expr $(,)?) => {{
@@ -649,6 +649,11 @@ fn test_vs1_vs2_vs3() {
649649
}
650650
}
651651

652+
#[test]
653+
fn test_char_iter() {
654+
assert_eq!(char_iter_width(['a', 'b', '🔬'].into_iter()), 4)
655+
}
656+
652657
// Test traits are unsealed
653658

654659
#[cfg(feature = "cjk")]

0 commit comments

Comments
 (0)