@@ -43,22 +43,67 @@ impl AsciiSet {
4343 pub const fn len ( & self ) -> usize {
4444 self . set . count_ones ( ) as usize
4545 }
46+
47+ #[ expect( clippy:: cast_possible_truncation) ]
48+ fn write_next_entry ( & mut self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
49+ let b = self . set . trailing_zeros ( ) as u8 ;
50+ let run = ( self . set >> b) . trailing_ones ( ) as u8 ;
51+
52+ let class_end = match b {
53+ b'0' ..=b'9' => b'9' ,
54+ b'a' ..=b'z' => b'z' ,
55+ b'A' ..=b'Z' => b'Z' ,
56+ _ => b,
57+ } ;
58+ let range_len = ( class_end - b + 1 ) . min ( run) ;
59+
60+ if range_len >= 4 {
61+ self . set &= !( ( ( 1 << range_len) - 1 ) << b) ;
62+ write ! ( f, "{:?}-{:?}" , b as char , ( b + range_len - 1 ) as char )
63+ } else {
64+ self . set &= !( 1 << b) ;
65+ write ! ( f, "{:?}" , b as char )
66+ }
67+ }
4668}
4769
70+ /// Format the set for display, combining digit and letter ranges.
71+ ///
72+ /// # Examples
73+ ///
74+ /// ```
75+ /// # use utils::ascii::AsciiSet;
76+ /// assert_eq!(
77+ /// AsciiSet::from(|b: u8| b.is_ascii_lowercase()).to_string(),
78+ /// "'a'-'z'"
79+ /// );
80+ /// assert_eq!(
81+ /// AsciiSet::from(|b: u8| b.is_ascii_alphabetic()).to_string(),
82+ /// "'A'-'Z', 'a'-'z'"
83+ /// );
84+ /// assert_eq!(
85+ /// AsciiSet::from(|b: u8| matches!(b, b'.' | b'#' | b'0'..=b'9')).to_string(),
86+ /// "'#', '.', '0'-'9'"
87+ /// );
88+ /// assert_eq!(
89+ /// AsciiSet::from(|b: u8| b.is_ascii_graphic()).to_string(),
90+ /// concat!(
91+ /// "'!', '\"', '#', '$', '%', '&', '\\'', '(', ')', '*', '+', ',', '-', '.', '/', ",
92+ /// "'0'-'9', ':', ';', '<', '=', '>', '?', '@', 'A'-'Z', '[', '\\\\', ']', '^', '_', ",
93+ /// "'`', 'a'-'z', '{', '|', '}', '~'"
94+ /// )
95+ /// );
96+ /// ```
4897impl Display for AsciiSet {
49- #[ expect( clippy:: cast_possible_truncation) ]
5098 fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
51- if self . set == 0 {
99+ if self . is_empty ( ) {
52100 return write ! ( f, "(empty)" ) ;
53101 }
54-
55- for ( i, ( c, _) ) in BitIterator :: ones ( self . set ) . enumerate ( ) {
56- let c = c as u8 as char ;
57- if i == 0 {
58- write ! ( f, "{c:?}" ) ?;
59- } else {
60- write ! ( f, ", {c:?}" ) ?;
61- }
102+ let mut set = * self ;
103+ set. write_next_entry ( f) ?;
104+ while !set. is_empty ( ) {
105+ write ! ( f, ", " ) ?;
106+ set. write_next_entry ( f) ?;
62107 }
63108 Ok ( ( ) )
64109 }
0 commit comments