1use core::ops::{Bound, RangeBounds};
2
3use crate::error::TryAdvanceError;
4
5use super::{
6 super::{must_non_zero, panic_advance},
7 ChunkMut, ChunkWriter,
8};
9
10#[derive(Debug)]
39pub struct Putter<B: ?Sized> {
40 cursor: usize,
42 start: Bound<usize>,
44 end: Bound<usize>,
46 limit: Bound<usize>,
48 buf: ChunkWriter<B>,
50}
51
52impl<B: ChunkMut> From<B> for Putter<B> {
53 #[inline]
54 fn from(buf: B) -> Self {
55 Self::new(buf)
56 }
57}
58
59impl<B> Putter<B> {
60 #[inline]
75 pub fn new(buf: impl Into<ChunkWriter<B>>) -> Self
76 where
77 B: ChunkMut,
78 {
79 Self::with_cursor_and_bounds_inner(buf.into(), 0, Bound::Included(0), Bound::Unbounded)
80 }
81
82 #[inline]
98 pub const fn const_new(buf: B) -> Self {
99 let buf = ChunkWriter::new(buf);
100 Self::with_cursor_and_bounds_inner(buf, 0, Bound::Included(0), Bound::Unbounded)
101 }
102
103 #[inline]
118 pub fn with_limit(buf: impl Into<ChunkWriter<B>>, limit: usize) -> Self {
119 let write_buf = buf.into();
120 Self::with_cursor_and_bounds_inner(write_buf, 0, Bound::Included(0), Bound::Excluded(limit))
121 }
122
123 #[inline]
138 pub const fn const_with_limit(buf: ChunkWriter<B>, limit: usize) -> Self {
139 Self::with_cursor_and_bounds_inner(buf, 0, Bound::Included(0), Bound::Excluded(limit))
140 }
141
142 #[inline]
160 pub fn with_range(buf: impl Into<ChunkWriter<B>>, range: impl RangeBounds<usize>) -> Self
161 where
162 B: ChunkMut,
163 {
164 let start = range.start_bound().cloned();
165 let end = range.end_bound().cloned();
166 let write_buf = buf.into();
167 let start_pos = Self::resolve_start_bound(start, &write_buf);
168 Self::with_cursor_and_bounds_inner(write_buf, start_pos, Bound::Included(start_pos), end)
169 }
170
171 #[inline]
190 pub const fn position(&self) -> usize {
191 let start_pos = Self::resolve_start_bound_without_check(self.start);
192 self.cursor.saturating_sub(start_pos)
193 }
194
195 #[inline]
213 pub const fn absolute_position(&self) -> usize {
214 self.cursor
215 }
216
217 #[inline]
241 pub const fn reset_position(&mut self) {
242 self.cursor = Self::resolve_start_bound_without_check(self.start);
243 self.limit = self.end;
244 }
245
246 pub fn reset(&mut self)
266 where
267 B: ChunkMut,
268 {
269 self.reset_position();
270 self.fill(0);
271 }
272
273 #[inline]
290 pub fn into_inner(self) -> B {
291 self.buf.0
292 }
293
294 #[inline]
295 const fn with_cursor_and_bounds_inner(
296 buf: ChunkWriter<B>,
297 cursor: usize,
298 start: Bound<usize>,
299 end: Bound<usize>,
300 ) -> Self {
301 Self {
302 buf,
303 cursor,
304 start,
305 end,
306 limit: end,
307 }
308 }
309
310 #[inline]
311 const fn resolve_start_bound_without_check(bound: Bound<usize>) -> usize {
312 match bound {
313 Bound::Included(n) => n,
314 Bound::Excluded(n) => n.saturating_add(1),
315 Bound::Unbounded => 0,
316 }
317 }
318}
319
320impl<B: ?Sized> Putter<B> {
321 #[inline]
322 fn resolve_start_bound(bound: Bound<usize>, buf: &ChunkWriter<B>) -> usize
323 where
324 B: ChunkMut,
325 {
326 let pos = match bound {
327 Bound::Included(n) => n,
328 Bound::Excluded(n) => n.saturating_add(1),
329 Bound::Unbounded => 0,
330 };
331 pos.min(buf.remaining_mut())
332 }
333
334 #[inline]
335 fn resolve_end_bound(&self, bound: Bound<usize>) -> usize
336 where
337 B: ChunkMut,
338 {
339 match bound {
340 Bound::Included(n) => (n.saturating_add(1)).min(self.buf.remaining_mut()),
341 Bound::Excluded(n) => n.min(self.buf.remaining_mut()),
342 Bound::Unbounded => self.buf.remaining_mut(),
343 }
344 }
345}
346
347impl<B: ChunkMut + ?Sized> ChunkMut for Putter<B> {
348 #[inline]
349 fn remaining_mut(&self) -> usize {
350 let end_pos = self.resolve_end_bound(self.limit);
351 end_pos.saturating_sub(self.cursor)
352 }
353
354 #[inline]
355 fn buffer_mut(&mut self) -> &mut [u8] {
356 let start = self.cursor.min(self.buf.remaining_mut());
357 let end_pos = self.resolve_end_bound(self.limit);
358 &mut self.buf.buffer_mut()[start..end_pos]
359 }
360
361 #[inline]
362 fn advance_mut(&mut self, cnt: usize) {
363 let remaining = self.remaining_mut();
364 if cnt > remaining {
365 panic_advance(&TryAdvanceError::new(must_non_zero(cnt), remaining));
366 }
367 self.cursor += cnt;
368 }
369
370 #[inline]
371 fn try_advance_mut(&mut self, cnt: usize) -> Result<(), TryAdvanceError> {
372 let remaining = self.remaining_mut();
373 if cnt > remaining {
374 return Err(TryAdvanceError::new(must_non_zero(cnt), remaining));
375 }
376 self.cursor += cnt;
377 Ok(())
378 }
379
380 #[inline]
381 fn truncate_mut(&mut self, new_len: usize) {
382 let current_remaining = self.remaining_mut();
383 if new_len >= current_remaining {
384 return; }
386
387 let new_end_pos = self.cursor + new_len;
388 let current_end_pos = self.resolve_end_bound(self.limit);
389
390 if new_end_pos < current_end_pos {
392 self.limit = Bound::Excluded(new_end_pos);
393 }
394 }
395}
396
397#[cfg(test)]
398mod tests {
399 use super::*;
400
401 #[test]
402 fn test_putter_basic_functionality() {
403 let mut data = [0u8; 10];
404 let mut putter = Putter::new(&mut data[..]);
405
406 assert_eq!(putter.remaining_mut(), 10);
407 assert_eq!(putter.position(), 0);
408
409 putter.write_u8(0x42);
411 assert_eq!(putter.remaining_mut(), 9);
412 assert_eq!(putter.position(), 1);
413
414 assert_eq!(data[0], 0x42);
416 }
417
418 #[test]
419 fn test_putter_ergonomic_api() {
420 let mut data = [0u8; 10];
422 let mut putter = Putter::new(&mut data[..]); putter.put_u8(0x11);
425 assert_eq!(data[0], 0x11);
426 }
427
428 #[test]
429 fn test_putter_with_limit() {
430 let mut data = [0u8; 10];
431 let mut putter = Putter::with_limit(&mut data[..], 3);
432
433 assert_eq!(putter.remaining_mut(), 3);
434
435 putter.write_u8(0x11);
437 putter.write_u8(0x22);
438 putter.write_u8(0x33);
439
440 assert_eq!(putter.remaining_mut(), 0);
442
443 assert_eq!(data[0], 0x11);
445 assert_eq!(data[1], 0x22);
446 assert_eq!(data[2], 0x33);
447 assert_eq!(data[3], 0x00); }
449
450 #[test]
451 fn test_putter_reset_position() {
452 let mut data = [0u8; 10];
453 let mut putter = Putter::new(&mut data[..]);
454
455 putter.advance_mut(3);
456 assert_eq!(putter.position(), 3);
457 assert_eq!(putter.remaining_mut(), 7);
458
459 putter.reset_position();
460 assert_eq!(putter.position(), 0);
461 assert_eq!(putter.remaining_mut(), 10);
462 }
463
464 #[test]
465 fn test_putter_truncate() {
466 let mut data = [0u8; 10];
467 let mut putter = Putter::new(&mut data[..]);
468
469 putter.truncate_mut(3);
470 assert_eq!(putter.remaining_mut(), 3);
471
472 putter.write_u8(0x11);
474 putter.write_u8(0x22);
475 putter.write_u8(0x33);
476 assert_eq!(putter.remaining_mut(), 0);
477
478 assert_eq!(data[0], 0x11);
480 assert_eq!(data[1], 0x22);
481 assert_eq!(data[2], 0x33);
482 assert_eq!(data[3], 0x00); }
484
485 #[test]
486 fn test_putter_try_advance() {
487 let mut data = [0u8; 5];
488 let mut putter = Putter::new(&mut data[..]);
489
490 assert!(putter.try_advance_mut(2).is_ok());
491 assert_eq!(putter.position(), 2);
492
493 assert!(putter.try_advance_mut(5).is_err());
495 assert_eq!(putter.position(), 2); }
497
498 #[test]
499 #[should_panic(expected = "advance")]
500 fn test_putter_advance_panic() {
501 let mut data = [0u8; 3];
502 let mut putter = Putter::new(&mut data[..]);
503
504 putter.advance_mut(5); }
506
507 #[test]
508 fn test_putter_with_different_integer_types() {
509 let mut data = [0u8; 20];
510 let mut putter = Putter::new(&mut data[..]);
511
512 putter.write_u16_le(0x1234);
514 putter.write_u32_le(0x56789ABC);
515 assert_eq!(putter.position(), 6);
516
517 assert_eq!(&data[0..2], &[0x34, 0x12]); assert_eq!(&data[2..6], &[0xBC, 0x9A, 0x78, 0x56]); }
521
522 #[test]
523 fn test_putter_write_slice() {
524 let mut data = [0u8; 10];
525 let mut putter = Putter::new(&mut data[..]);
526
527 let test_data = [0x11, 0x22, 0x33, 0x44];
528 putter.write_slice(&test_data);
529
530 assert_eq!(putter.position(), 4);
531 assert_eq!(&data[0..4], &test_data);
532 assert_eq!(data[4], 0x00); }
534
535 #[test]
536 fn test_putter_with_advanced_buffer() {
537 let mut data = [0u8; 10];
538 let mut buf = &mut data[..];
539
540 buf.advance_mut(3);
542 assert_eq!(buf.remaining_mut(), 7);
543
544 let mut putter = Putter::new(buf);
546 assert_eq!(putter.remaining_mut(), 7);
547 putter.put_u8(0x42);
548 assert_eq!(data[3], 0x42); }
551
552 #[test]
553 fn test_putter_buffer_mut_access() {
554 let mut data = [0u8; 10];
555 let mut putter = Putter::new(&mut data[..]);
556
557 putter.write_u8(0x11);
559 putter.write_u8(0x22);
560
561 let remaining_buffer = putter.buffer_mut();
563 remaining_buffer[0] = 0x99; assert_eq!(data[0], 0x11);
566 assert_eq!(data[1], 0x22);
567 assert_eq!(data[2], 0x99);
568 }
569
570 #[test]
571 fn test_putter_state_consistency() {
572 let mut data = [0u8; 10];
573 let mut putter = Putter::new(&mut data[..]);
574
575 let initial_remaining = putter.remaining_mut();
577 let initial_written = putter.position();
578
579 putter.advance_mut(3);
581 assert_eq!(
582 putter.remaining_mut() + putter.position(),
583 initial_remaining
584 );
585
586 putter.truncate_mut(5);
588 assert_eq!(putter.remaining_mut(), 5);
589 assert_eq!(putter.position(), 3);
590
591 putter.reset_position();
593 assert_eq!(putter.position(), initial_written);
594 assert_eq!(putter.remaining_mut(), initial_remaining); }
596
597 #[test]
598 fn test_putter_exhaustive_write() {
599 let mut data = [0u8; 3];
600 let mut putter = Putter::new(&mut data[..]);
601
602 assert_eq!(putter.write_u8(0x11), 1);
604 assert_eq!(putter.remaining_mut(), 2);
605
606 assert_eq!(putter.write_u8(0x22), 1);
607 assert_eq!(putter.remaining_mut(), 1);
608
609 assert_eq!(putter.write_u8(0x33), 1);
610 assert_eq!(putter.remaining_mut(), 0);
611
612 assert_eq!(data, [0x11, 0x22, 0x33]);
614 }
615
616 #[test]
617 fn test_putter_from_trait() {
618 let mut data = [0u8; 10];
619
620 let putter: Putter<_> = (&mut data[..]).into();
622 assert_eq!(putter.remaining_mut(), 10);
623 }
624
625 #[test]
626 fn test_putter_endianness() {
627 let mut data = [0u8; 16];
628 let mut putter = Putter::new(&mut data[..]);
629
630 putter.write_u16_le(0x1234);
632 putter.write_u16_be(0x1234);
633 putter.write_u32_le(0x12345678);
634 putter.write_u32_be(0x12345678);
635
636 assert_eq!(&data[0..2], &[0x34, 0x12]);
638 assert_eq!(&data[2..4], &[0x12, 0x34]);
640 assert_eq!(&data[4..8], &[0x78, 0x56, 0x34, 0x12]);
642 assert_eq!(&data[8..12], &[0x12, 0x34, 0x56, 0x78]);
644 }
645
646 #[test]
647 fn test_putter_signed_values() {
648 let mut data = [0u8; 10];
649 let mut putter = Putter::new(&mut data[..]);
650
651 putter.write_i8(-1);
653 putter.write_i16_le(-1);
654 putter.write_i32_be(-1);
655
656 assert_eq!(data[0], 0xFF);
658 assert_eq!(&data[1..3], &[0xFF, 0xFF]);
660 assert_eq!(&data[3..7], &[0xFF, 0xFF, 0xFF, 0xFF]);
662 }
663
664 #[test]
665 fn test_putter_reset_position_preserves_limits() {
666 let mut data = [0u8; 10];
667 let mut putter = Putter::with_limit(&mut data[..], 5);
668
669 putter.advance_mut(3);
670 assert_eq!(putter.position(), 3);
671 assert_eq!(putter.remaining_mut(), 2);
672
673 putter.reset_position();
674 assert_eq!(putter.position(), 0);
675 assert_eq!(putter.remaining_mut(), 5); }
677
678 #[test]
679 fn test_putter_truncate_after_advance() {
680 let mut data = [0u8; 10];
681 let mut putter = Putter::new(&mut data[..]);
682
683 putter.advance_mut(3);
684 assert_eq!(putter.remaining_mut(), 7);
685
686 putter.truncate_mut(4);
687 assert_eq!(putter.remaining_mut(), 4);
688
689 putter.write_slice(&[0x11, 0x22, 0x33, 0x44]);
691 assert_eq!(putter.remaining_mut(), 0);
692
693 assert_eq!(&data[3..7], &[0x11, 0x22, 0x33, 0x44]);
695 }
696
697 #[test]
698 fn test_putter_truncate_limited_putter() {
699 let mut data = [0u8; 10];
700 let mut putter = Putter::with_limit(&mut data[..], 6);
701
702 assert_eq!(putter.remaining_mut(), 6);
703
704 putter.truncate_mut(4);
706 assert_eq!(putter.remaining_mut(), 4);
707
708 putter.truncate_mut(2);
710 assert_eq!(putter.remaining_mut(), 2);
711 }
712
713 #[test]
714 fn test_error_details() {
715 let mut data = [0u8; 3];
716 let mut putter = Putter::new(&mut data[..]);
717
718 let advance_err = putter.try_advance_mut(5).unwrap_err();
720 assert_eq!(advance_err.requested().get(), 5);
721 assert_eq!(advance_err.available(), 3);
722 }
723
724 #[test]
725 fn test_putter_large_data() {
726 let mut large_data = [0u8; 1000];
728 let mut putter = Putter::new(&mut large_data[..]);
729
730 assert_eq!(putter.remaining_mut(), 1000);
731
732 for i in 0..100 {
734 putter.write_u8(i as u8);
735 }
736
737 assert_eq!(putter.remaining_mut(), 900);
738 assert_eq!(putter.position(), 100);
739
740 #[allow(clippy::needless_range_loop)]
742 for i in 0..100 {
743 assert_eq!(large_data[i], i as u8);
744 }
745 }
746
747 #[test]
748 fn test_putter_boundary_conditions() {
749 let mut single_byte = [0u8; 1];
751 let mut putter = Putter::new(&mut single_byte[..]);
752
753 assert_eq!(putter.remaining_mut(), 1);
754 putter.write_u8(0x42);
755 assert_eq!(putter.remaining_mut(), 0);
756
757 assert!(putter.try_advance_mut(1).is_err());
759 assert_eq!(putter.put_u8_checked(0x99), None);
760 assert!(putter.try_put_u8(0x99).is_err());
761
762 putter.reset_position();
764 assert_eq!(putter.remaining_mut(), 1);
765 }
766
767 #[test]
768 fn test_putter_with_limit_larger_than_buffer() {
769 let mut data = [0u8; 3];
770 let putter = Putter::with_limit(&mut data[..], 10);
771
772 assert_eq!(putter.remaining_mut(), 3);
774 }
775
776 #[test]
777 fn test_putter_with_limit_zero() {
778 let mut data = [0u8; 5];
779 let putter = Putter::with_limit(&mut data[..], 0);
780
781 assert_eq!(putter.remaining_mut(), 0);
782 }
783
784 #[test]
785 fn test_written_calculation() {
786 let mut data = [0u8; 10];
787 let mut putter = Putter::new(&mut data[..]);
788
789 assert_eq!(putter.position(), 0);
791
792 putter.advance_mut(2);
793 assert_eq!(putter.position(), 2);
794
795 putter.write_u8(0x42);
796 assert_eq!(putter.position(), 3);
797
798 putter.write_slice(&[1, 2, 3]);
799 assert_eq!(putter.position(), 6);
800
801 putter.reset_position();
803 assert_eq!(putter.position(), 0);
804 }
805
806 #[test]
807 fn test_putter_ergonomic_comparison() {
808 let mut data = [0u8; 10];
809
810 let mut putter = Putter::new(&mut data[..]); putter.write_u8(0x42);
818 assert_eq!(putter.position(), 1);
819
820 assert_eq!(data[0], 0x42);
821 }
822
823 #[test]
824 fn test_putter_with_range() {
825 let mut data = [0u8; 10];
826 let mut putter = Putter::with_range(&mut data[..], 2..=8);
827
828 assert_eq!(putter.remaining_mut(), 7);
829
830 putter.write_u8(0x42);
831 assert_eq!(putter.position(), 1);
832 putter.reset();
833 assert_eq!(data[2], 0);
834
835 let mut putter = Putter::with_range(&mut data[..], ..7);
836 assert_eq!(putter.remaining_mut(), 7);
837 putter.write_u8(0x99);
838 assert_eq!(putter.position(), 1);
839 putter.reset();
840 assert_eq!(data[0], 0);
841
842 let mut putter = Putter::with_range(&mut data[..], (Bound::Excluded(1), Bound::Unbounded));
843 assert_eq!(putter.remaining_mut(), 8);
844 putter.write_u8(0x77);
845 assert_eq!(putter.position(), 1);
846 putter.reset();
847 assert_eq!(data[2], 0);
848 }
849}