facet_diff_core/layout/
arena.rs1use std::fmt;
4use unicode_width::UnicodeWidthStr;
5
6#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
8pub struct Span {
9 pub start: u32,
11 pub end: u32,
13}
14
15impl Span {
16 #[inline]
18 pub fn len(self) -> usize {
19 (self.end - self.start) as usize
20 }
21
22 #[inline]
24 pub fn is_empty(self) -> bool {
25 self.start == self.end
26 }
27}
28
29pub struct FormatArena {
34 buf: String,
35}
36
37impl FormatArena {
38 pub fn with_capacity(cap: usize) -> Self {
40 Self {
41 buf: String::with_capacity(cap),
42 }
43 }
44
45 pub fn new() -> Self {
47 Self::with_capacity(4096)
49 }
50
51 pub fn format<F>(&mut self, f: F) -> (Span, usize)
57 where
58 F: FnOnce(&mut String) -> fmt::Result,
59 {
60 let start = self.buf.len();
61 f(&mut self.buf).expect("formatting to String cannot fail");
62 let end = self.buf.len();
63 let span = Span {
64 start: start as u32,
65 end: end as u32,
66 };
67 let width = self.buf[start..end].width();
68 (span, width)
69 }
70
71 pub fn push_str(&mut self, s: &str) -> (Span, usize) {
73 let start = self.buf.len();
74 self.buf.push_str(s);
75 let span = Span {
76 start: start as u32,
77 end: self.buf.len() as u32,
78 };
79 let width = s.width();
80 (span, width)
81 }
82
83 #[inline]
85 pub fn get(&self, span: Span) -> &str {
86 &self.buf[span.start as usize..span.end as usize]
87 }
88
89 pub fn len(&self) -> usize {
91 self.buf.len()
92 }
93
94 pub fn is_empty(&self) -> bool {
96 self.buf.is_empty()
97 }
98}
99
100impl Default for FormatArena {
101 fn default() -> Self {
102 Self::new()
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use std::fmt::Write;
109
110 use super::*;
111
112 #[test]
113 fn test_format_simple() {
114 let mut arena = FormatArena::new();
115 let (span, width) = arena.format(|w| write!(w, "hello"));
116 assert_eq!(arena.get(span), "hello");
117 assert_eq!(width, 5);
118 }
119
120 #[test]
121 fn test_format_multiple() {
122 let mut arena = FormatArena::new();
123
124 let (s1, w1) = arena.format(|w| write!(w, "hello"));
125 let (s2, w2) = arena.format(|w| write!(w, "world"));
126
127 assert_eq!(arena.get(s1), "hello");
128 assert_eq!(arena.get(s2), "world");
129 assert_eq!(w1, 5);
130 assert_eq!(w2, 5);
131
132 assert_eq!(s1.end, s2.start);
134 }
135
136 #[test]
137 fn test_format_unicode() {
138 let mut arena = FormatArena::new();
139
140 let (span, width) = arena.format(|w| write!(w, "日本語"));
142 assert_eq!(arena.get(span), "日本語");
143 assert_eq!(width, 6); let (span, width) = arena.format(|w| write!(w, "🦀"));
147 assert_eq!(arena.get(span), "🦀");
148 assert_eq!(width, 2); }
150
151 #[test]
152 fn test_push_str() {
153 let mut arena = FormatArena::new();
154 let (span, width) = arena.push_str("test");
155 assert_eq!(arena.get(span), "test");
156 assert_eq!(width, 4);
157 }
158
159 #[test]
160 fn test_span_len() {
161 let span = Span { start: 10, end: 20 };
162 assert_eq!(span.len(), 10);
163 assert!(!span.is_empty());
164
165 let empty = Span { start: 5, end: 5 };
166 assert_eq!(empty.len(), 0);
167 assert!(empty.is_empty());
168 }
169}