1#![allow(unknown_lints)]
2#![allow(clippy::manual_dangling_ptr)]
3
4use alloc::{
27 alloc::{alloc, dealloc, handle_alloc_error, realloc},
28 boxed::Box,
29 string::String,
30};
31use core::{
32 alloc::Layout,
33 cmp, fmt,
34 mem::ManuallyDrop,
35 ops::{Add, AddAssign},
36 ptr, slice, str,
37};
38
39pub struct Buffer {
44 data: *mut u8,
45 len: usize,
46 capacity: usize,
47}
48
49impl Buffer {
50 #[inline]
52 pub const fn new() -> Buffer {
53 Self {
54 data: align_of::<u8>() as *mut u8, len: 0,
56 capacity: 0,
57 }
58 }
59
60 #[inline]
62 pub fn with_capacity(n: usize) -> Buffer {
63 if n == 0 {
64 Self::new()
65 } else {
66 Self {
67 data: safe_alloc(n),
68 len: 0,
69 capacity: n,
70 }
71 }
72 }
73
74 #[inline]
76 pub fn as_str(&self) -> &str {
77 unsafe {
78 let bytes = slice::from_raw_parts(self.data, self.len);
79 str::from_utf8_unchecked(bytes)
80 }
81 }
82
83 #[inline]
85 pub fn as_mut_ptr(&self) -> *mut u8 {
86 self.data
87 }
88
89 #[inline]
91 pub fn len(&self) -> usize {
92 self.len
93 }
94
95 #[inline]
97 pub fn capacity(&self) -> usize {
98 self.capacity
99 }
100
101 #[inline]
102 #[doc(hidden)]
103 pub unsafe fn _set_len(&mut self, new_len: usize) {
104 debug_assert!(new_len <= self.capacity);
105 self.len = new_len;
106 }
107
108 #[inline]
115 pub unsafe fn advance(&mut self, additional: usize) {
116 self.len += additional;
117 }
118
119 #[inline]
122 pub fn is_empty(&self) -> bool {
123 self.len == 0
124 }
125
126 #[inline]
132 pub fn reserve(&mut self, size: usize) {
133 if size <= self.capacity - self.len {
134 return;
135 }
136 self.reserve_internal(size);
137 }
138
139 #[inline]
142 pub(crate) unsafe fn reserve_small(&mut self, size: usize) {
143 debug_assert!(size <= isize::MAX as usize);
144 if self.len + size <= self.capacity {
145 return;
146 }
147 self.reserve_internal(size);
148 }
149
150 #[inline]
151 #[doc(hidden)]
152 pub fn clear(&mut self) {
153 self.len = 0;
154 }
155
156 #[inline]
158 pub fn into_string(self) -> String {
159 debug_assert!(self.len <= self.capacity);
160 let buf = ManuallyDrop::new(self);
161
162 unsafe { String::from_raw_parts(buf.data, buf.len, buf.capacity) }
165 }
166
167 #[inline]
169 pub fn push_str(&mut self, data: &str) {
170 let size = data.len();
171
172 unsafe {
173 self.reserve_small(size);
177
178 let p = self.data.add(self.len);
179 ptr::copy_nonoverlapping(data.as_ptr(), p, size);
180 self.len += size;
181 }
182 debug_assert!(self.len <= self.capacity);
183 }
184
185 #[inline]
187 pub fn push(&mut self, data: char) {
188 unsafe {
191 self.reserve_small(4);
192 let bp = self.data.add(self.len) as *mut [u8; 4];
193 let result = data.encode_utf8(&mut *bp);
194 self.len += result.len();
195 }
196 }
197
198 #[inline]
199 fn reserve_internal(&mut self, size: usize) {
200 debug_assert!(size <= isize::MAX as usize);
201
202 let new_capacity = cmp::max(self.capacity * 2, self.capacity + size);
203 debug_assert!(new_capacity > self.capacity);
204 self.data =
205 unsafe { safe_realloc(self.data, self.capacity, new_capacity) };
206 self.capacity = new_capacity;
207
208 debug_assert!(!self.data.is_null());
209 debug_assert!(self.len <= self.capacity);
210 }
211}
212
213#[inline(never)]
214fn safe_alloc(capacity: usize) -> *mut u8 {
215 assert!(capacity > 0);
216 assert!(capacity <= isize::MAX as usize, "capacity is too large");
217
218 unsafe {
220 let layout = Layout::from_size_align_unchecked(capacity, 1);
221 let data = alloc(layout);
222 if data.is_null() {
223 handle_alloc_error(layout);
224 }
225
226 data
227 }
228}
229
230#[cold]
235#[inline(never)]
236unsafe fn safe_realloc(
237 ptr: *mut u8,
238 capacity: usize,
239 new_capacity: usize,
240) -> *mut u8 {
241 assert!(new_capacity > 0);
242 assert!(new_capacity <= isize::MAX as usize, "capacity is too large");
243
244 let data = if capacity == 0 {
245 let new_layout = Layout::from_size_align_unchecked(new_capacity, 1);
246 alloc(new_layout)
247 } else {
248 let old_layout = Layout::from_size_align_unchecked(capacity, 1);
249 realloc(ptr, old_layout, new_capacity)
250 };
251
252 if data.is_null() {
253 handle_alloc_error(Layout::from_size_align_unchecked(new_capacity, 1));
254 }
255
256 data
257}
258
259impl Clone for Buffer {
260 fn clone(&self) -> Self {
261 unsafe {
262 if self.is_empty() {
263 Self::new()
264 } else {
265 let buf = Self {
266 data: safe_alloc(self.len),
267 len: self.len,
268 capacity: self.len,
269 };
270
271 ptr::copy_nonoverlapping(self.data, buf.data, self.len);
272 buf
273 }
274 }
275 }
276}
277
278impl fmt::Debug for Buffer {
279 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
280 self.as_str().fmt(f)
281 }
282}
283
284impl Drop for Buffer {
285 fn drop(&mut self) {
286 if self.capacity != 0 {
287 unsafe {
291 let layout =
292 Layout::from_size_align_unchecked(self.capacity, 1);
293 dealloc(self.data, layout);
294 }
295 }
296 }
297}
298
299impl fmt::Write for Buffer {
300 #[inline]
301 fn write_str(&mut self, s: &str) -> fmt::Result {
302 Buffer::push_str(self, s);
303 Ok(())
304 }
305}
306
307impl From<String> for Buffer {
308 #[inline]
312 fn from(other: String) -> Buffer {
313 let bs = other.into_boxed_str();
314 let data = Box::leak(bs);
315 Buffer {
316 data: data.as_mut_ptr(),
317 len: data.len(),
318 capacity: data.len(),
319 }
320 }
321}
322
323impl From<&str> for Buffer {
324 #[inline]
325 fn from(other: &str) -> Buffer {
326 let mut buf = Buffer::with_capacity(other.len());
327
328 if !other.is_empty() {
329 unsafe {
333 ptr::copy_nonoverlapping(
334 other.as_ptr(),
335 buf.as_mut_ptr(),
336 other.len(),
337 );
338 buf.advance(other.len());
339 }
340 }
341
342 buf
343 }
344}
345
346impl Add<&str> for Buffer {
347 type Output = Buffer;
348
349 #[inline]
350 fn add(mut self, other: &str) -> Buffer {
351 self.push_str(other);
352 self
353 }
354}
355
356impl AddAssign<&str> for Buffer {
357 #[inline]
358 fn add_assign(&mut self, other: &str) {
359 self.push_str(other)
360 }
361}
362
363impl Default for Buffer {
364 #[inline]
365 fn default() -> Buffer {
366 Buffer::new()
367 }
368}
369
370unsafe impl Send for Buffer {}
371unsafe impl Sync for Buffer {}
372
373#[cfg(test)]
374mod tests {
375 use alloc::vec::Vec;
376 use std::{
377 sync::{Arc, Barrier, Mutex},
378 thread,
379 };
380
381 use super::*;
382
383 #[test]
384 fn push_str() {
385 let mut buffer = Buffer::new();
386 assert_eq!(buffer.len(), 0);
387 assert_eq!(buffer.capacity(), 0);
388
389 buffer.push_str("apple");
390 assert_eq!(buffer.len(), 5);
391 assert_eq!(buffer.capacity(), 5);
392
393 buffer.push_str("pie");
394 assert_eq!(buffer.len(), 8);
395 assert_eq!(buffer.capacity(), 10);
396
397 for _ in 0..16 {
398 buffer.push_str("zomg");
399 }
400
401 assert_eq!(buffer.len(), 72);
402 assert_eq!(buffer.capacity(), 80);
403 }
404
405 #[test]
406 fn with_capacity() {
407 let buffer = Buffer::with_capacity(1);
408 assert!(buffer.is_empty());
409 assert_eq!(buffer.len(), 0);
410 assert!(buffer.capacity() >= 1);
411 }
412
413 #[test]
414 fn string_conversion() {
415 let s = String::with_capacity(2);
417 assert!(s.capacity() >= 2);
418
419 let mut buf = Buffer::from(s);
420 assert_eq!(buf.as_str(), "");
421
422 assert_eq!(buf.capacity(), 0);
424
425 buf.push_str("abc");
426 assert_eq!(buf.as_str(), "abc");
427
428 let mut s = buf.into_string();
430 assert_eq!(s, "abc");
431
432 s += "defghijklmn";
433 assert_eq!(s, "abcdefghijklmn");
434
435 let mut buf = Buffer::from(s);
437 assert_eq!(buf.as_str(), "abcdefghijklmn");
438 buf.clear();
439 assert_eq!(buf.as_str(), "");
440
441 let buf = Buffer::default();
443 let mut s = buf.into_string();
444 assert_eq!(s, "");
445
446 s.push_str("apple");
447 assert_eq!(s, "apple");
448 }
449
450 #[test]
451 fn from_str() {
452 let buf = Buffer::from("abcdefgh");
453 assert_eq!(buf.as_str(), "abcdefgh");
454 }
455
456 #[test]
457 fn clone() {
458 use core::fmt::Write;
459
460 let mut s1 = Buffer::with_capacity(0);
461 let mut s2 = s1.clone();
462
463 s1.push('a');
464 s2.push_str("b");
465
466 assert_eq!(s1.as_str(), "a");
467 assert_eq!(s2.as_str(), "b");
468
469 let mut s1 = Buffer::from("foo");
470 let mut s2 = s1.clone();
471
472 s1 += "bar";
473 write!(s2, "baz").unwrap();
474
475 assert_eq!(s1.as_str(), "foobar");
476 assert_eq!(s2.as_str(), "foobaz");
477
478 s2.clear();
479 let _ = s2.clone();
480 }
481
482 #[test]
483 fn push() {
484 for initial_capacity in &[0, 4, 16] {
485 let mut s = Buffer::with_capacity(*initial_capacity);
486
487 s.push('a');
488 s.push('é');
489 s.push('A');
490 s.push('🄫');
491
492 assert_eq!(s.as_str(), "aéA🄫");
493 }
494 }
495
496 #[test]
497 fn multi_thread() {
498 const THREADS: usize = 8;
499 const ITERS: usize = 100;
500
501 let barrier = Arc::new(Barrier::new(THREADS));
502 let buffer = Arc::new(Mutex::new(Buffer::new()));
503 let mut handles = Vec::with_capacity(THREADS);
504
505 for _ in 0..THREADS {
506 let barrier = barrier.clone();
507 let buffer = buffer.clone();
508
509 handles.push(thread::spawn(move || {
510 barrier.wait();
511 for _ in 0..ITERS {
512 buffer.lock().unwrap().push_str("a");
513 }
514 }));
515 }
516
517 for handle in handles {
518 handle.join().unwrap();
519 }
520
521 assert_eq!(
522 buffer.lock().unwrap().as_str(),
523 "a".repeat(ITERS * THREADS)
524 );
525 }
526
527 #[test]
528 #[should_panic]
529 fn reserve_overflow() {
530 let mut buf = Buffer::new();
531 buf.reserve(isize::MAX as usize + 1);
532 }
533
534 #[test]
535 #[should_panic]
536 fn empty_alloc() {
537 safe_alloc(0);
538 }
539}