1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
//! Module for stacking line-drawing characters on top of each other. //! //! # Examples //! //! ``` //! let combo = unicode_line_stacker::stack('┌', '┴'); //! assert_eq!(Some('┼'), combo); //! //! // Bit string format: for each of the four directions, clockwise starting from //! // top (least significant to most significant), 1 means "on" and 0 means "off." //! let c = unicode_line_stacker::bits_to_char(0b1011); //! assert_eq!('┴', c); //! ``` /// Stack two line-drawing characters on top of each other and return the result. /// /// Returns `None` if one or both of the input characters are unsupported. /// /// # Examples /// /// ``` /// let a = '─'; /// let b = '│'; /// let result = unicode_line_stacker::stack(a, b); /// assert_eq!(Some('┼'), result); /// ``` pub fn stack(a: char, b: char) -> Option<char> { let look_for_a = char_to_bits(a); let look_for_b = char_to_bits(b); if look_for_b.is_none() || look_for_b.is_none() { None } else { Some(LINE_DRAWING_CHARS[look_for_a.unwrap() | look_for_b.unwrap()]) } } /// Convert a line-drawing char to a bitset (or None if the char is unsupported). /// /// # Examples /// /// ``` /// let c = '┬'; /// let result = unicode_line_stacker::char_to_bits(c); /// assert_eq!(Some(0b1110), result); /// ``` #[inline] pub fn char_to_bits(c: char) -> Option<usize> { // It's likely faster to iterate through 16 chars than it is to try some // HashMap trickery. LINE_DRAWING_CHARS .iter() .enumerate() .find(|&(_, &c2)| c == c2) .map(|tup| tup.0) } /// Convert a bitset to a line-drawing char. /// /// This crate's representation of each line-drawing char is a `u32` /// representing a bitset: starting from least significant bit, the bits /// represent up, right, down, left, in that order. /// /// # Examples /// /// ``` /// assert_eq!('┤', unicode_line_stacker::bits_to_char(0b1101)); /// ``` /// /// # Panics /// /// Panics if `bits >= 16`. #[inline] pub fn bits_to_char(bits: u32) -> char { if bits >= 16 { panic!( "Bit set must be between 0 and 15 inclusive but got {}", bits ); } LINE_DRAWING_CHARS[bits as usize] } const LINE_DRAWING_CHARS: [char; 16] = [ ' ', // 0000 '\u{2575}', // 0001 '\u{2576}', // 0010 '\u{2514}', // 0011 '\u{2577}', // 0100 '\u{2502}', // 0101 '\u{250c}', // 0110 '\u{251c}', // 0111 '\u{2574}', // 1000 '\u{2518}', // 1001 '\u{2500}', // 1010 '\u{2534}', // 1011 '\u{2510}', // 1100 '\u{2524}', // 1101 '\u{252c}', // 1110 '\u{253c}', // 1111 ]; #[cfg(test)] mod tests { use super::*; #[test] fn stack_with_empty() { let base_char = '\u{2514}'; // light up and right let result = stack(' ', base_char); assert_eq!(Some(base_char), result); } #[test] #[should_panic(expected = "but got 16")] fn bits_to_char_panics_on_input_16() { bits_to_char(16); } }