1use core::ops::{Bound, RangeBounds};
2
3use crate::error::TryAdvanceError;
4
5use super::{ChunkMut, ChunkWriter};
6
7#[derive(Debug)]
36pub struct Putter<B: ?Sized> {
37 cursor: usize,
39 start: Bound<usize>,
41 end: Bound<usize>,
43 limit: Bound<usize>,
45 buf: ChunkWriter<B>,
47}
48
49impl<B: ChunkMut> From<B> for Putter<B> {
50 #[inline]
51 fn from(buf: B) -> Self {
52 Self::new(buf)
53 }
54}
55
56impl<B> Putter<B> {
57 #[inline]
72 pub fn new(buf: impl Into<ChunkWriter<B>>) -> Self
73 where
74 B: ChunkMut,
75 {
76 Self::with_cursor_and_bounds_inner(buf.into(), 0, Bound::Included(0), Bound::Unbounded)
77 }
78
79 #[inline]
95 pub const fn const_new(buf: B) -> Self {
96 let buf = ChunkWriter::new(buf);
97 Self::with_cursor_and_bounds_inner(buf, 0, Bound::Included(0), Bound::Unbounded)
98 }
99
100 #[inline]
115 pub fn with_limit(buf: impl Into<ChunkWriter<B>>, limit: usize) -> Self {
116 let write_buf = buf.into();
117 Self::with_cursor_and_bounds_inner(write_buf, 0, Bound::Included(0), Bound::Excluded(limit))
118 }
119
120 #[inline]
135 pub const fn const_with_limit(buf: ChunkWriter<B>, limit: usize) -> Self {
136 Self::with_cursor_and_bounds_inner(buf, 0, Bound::Included(0), Bound::Excluded(limit))
137 }
138
139 #[inline]
157 pub fn with_range(buf: impl Into<ChunkWriter<B>>, range: impl RangeBounds<usize>) -> Self
158 where
159 B: ChunkMut,
160 {
161 let start = range.start_bound().cloned();
162 let end = range.end_bound().cloned();
163 let write_buf = buf.into();
164 let start_pos = Self::resolve_start_bound(start, &write_buf);
165 Self::with_cursor_and_bounds_inner(write_buf, start_pos, Bound::Included(start_pos), end)
166 }
167
168 #[inline]
187 pub const fn position(&self) -> usize {
188 let start_pos = Self::resolve_start_bound_without_check(self.start);
189 self.cursor.saturating_sub(start_pos)
190 }
191
192 #[inline]
210 pub const fn absolute_position(&self) -> usize {
211 self.cursor
212 }
213
214 #[inline]
238 pub const fn reset_position(&mut self) {
239 self.cursor = Self::resolve_start_bound_without_check(self.start);
240 self.limit = self.end;
241 }
242
243 pub fn reset(&mut self)
263 where
264 B: ChunkMut,
265 {
266 self.reset_position();
267 self.fill(0);
268 }
269
270 #[inline]
287 pub fn into_inner(self) -> B {
288 self.buf.0
289 }
290
291 #[inline]
292 const fn with_cursor_and_bounds_inner(
293 buf: ChunkWriter<B>,
294 cursor: usize,
295 start: Bound<usize>,
296 end: Bound<usize>,
297 ) -> Self {
298 Self {
299 buf,
300 cursor,
301 start,
302 end,
303 limit: end,
304 }
305 }
306
307 #[inline]
308 const fn resolve_start_bound_without_check(bound: Bound<usize>) -> usize {
309 match bound {
310 Bound::Included(n) => n,
311 Bound::Excluded(n) => n.saturating_add(1),
312 Bound::Unbounded => 0,
313 }
314 }
315}
316
317impl<B: ?Sized> Putter<B> {
318 #[inline]
319 fn resolve_start_bound(bound: Bound<usize>, buf: &ChunkWriter<B>) -> usize
320 where
321 B: ChunkMut,
322 {
323 let pos = match bound {
324 Bound::Included(n) => n,
325 Bound::Excluded(n) => n.saturating_add(1),
326 Bound::Unbounded => 0,
327 };
328 pos.min(buf.remaining_mut())
329 }
330
331 #[inline]
332 fn resolve_end_bound(&self, bound: Bound<usize>) -> usize
333 where
334 B: ChunkMut,
335 {
336 match bound {
337 Bound::Included(n) => (n.saturating_add(1)).min(self.buf.remaining_mut()),
338 Bound::Excluded(n) => n.min(self.buf.remaining_mut()),
339 Bound::Unbounded => self.buf.remaining_mut(),
340 }
341 }
342}
343
344impl<B: ChunkMut + ?Sized> ChunkMut for Putter<B> {
345 #[inline]
346 fn remaining_mut(&self) -> usize {
347 let end_pos = self.resolve_end_bound(self.limit);
348 end_pos.saturating_sub(self.cursor)
349 }
350
351 #[inline]
352 fn buffer_mut(&mut self) -> &mut [u8] {
353 let start = self.cursor.min(self.buf.remaining_mut());
354 let end_pos = self.resolve_end_bound(self.limit);
355 &mut self.buf.buffer_mut()[start..end_pos]
356 }
357
358 #[inline]
359 fn advance_mut(&mut self, cnt: usize) {
360 let remaining = self.remaining_mut();
361 if cnt > remaining {
362 super::panic_advance(&TryAdvanceError::new(cnt, remaining));
363 }
364 self.cursor += cnt;
365 }
366
367 #[inline]
368 fn try_advance_mut(&mut self, cnt: usize) -> Result<(), TryAdvanceError> {
369 let remaining = self.remaining_mut();
370 if cnt > remaining {
371 return Err(TryAdvanceError::new(cnt, remaining));
372 }
373 self.cursor += cnt;
374 Ok(())
375 }
376
377 #[inline]
378 fn truncate_mut(&mut self, new_len: usize) {
379 let current_remaining = self.remaining_mut();
380 if new_len >= current_remaining {
381 return; }
383
384 let new_end_pos = self.cursor + new_len;
385 let current_end_pos = self.resolve_end_bound(self.limit);
386
387 if new_end_pos < current_end_pos {
389 self.limit = Bound::Excluded(new_end_pos);
390 }
391 }
392}
393
394#[cfg(test)]
395mod tests {
396 use super::*;
397
398 #[test]
399 fn test_putter_basic_functionality() {
400 let mut data = [0u8; 10];
401 let mut putter = Putter::new(&mut data[..]);
402
403 assert_eq!(putter.remaining_mut(), 10);
404 assert_eq!(putter.position(), 0);
405
406 putter.write_u8(0x42);
408 assert_eq!(putter.remaining_mut(), 9);
409 assert_eq!(putter.position(), 1);
410
411 assert_eq!(data[0], 0x42);
413 }
414
415 #[test]
416 fn test_putter_ergonomic_api() {
417 let mut data = [0u8; 10];
419 let mut putter = Putter::new(&mut data[..]); putter.put_u8(0x11);
422 assert_eq!(data[0], 0x11);
423 }
424
425 #[test]
426 fn test_putter_with_limit() {
427 let mut data = [0u8; 10];
428 let mut putter = Putter::with_limit(&mut data[..], 3);
429
430 assert_eq!(putter.remaining_mut(), 3);
431
432 putter.write_u8(0x11);
434 putter.write_u8(0x22);
435 putter.write_u8(0x33);
436
437 assert_eq!(putter.remaining_mut(), 0);
439
440 assert_eq!(data[0], 0x11);
442 assert_eq!(data[1], 0x22);
443 assert_eq!(data[2], 0x33);
444 assert_eq!(data[3], 0x00); }
446
447 #[test]
448 fn test_putter_reset_position() {
449 let mut data = [0u8; 10];
450 let mut putter = Putter::new(&mut data[..]);
451
452 putter.advance_mut(3);
453 assert_eq!(putter.position(), 3);
454 assert_eq!(putter.remaining_mut(), 7);
455
456 putter.reset_position();
457 assert_eq!(putter.position(), 0);
458 assert_eq!(putter.remaining_mut(), 10);
459 }
460
461 #[test]
462 fn test_putter_truncate() {
463 let mut data = [0u8; 10];
464 let mut putter = Putter::new(&mut data[..]);
465
466 putter.truncate_mut(3);
467 assert_eq!(putter.remaining_mut(), 3);
468
469 putter.write_u8(0x11);
471 putter.write_u8(0x22);
472 putter.write_u8(0x33);
473 assert_eq!(putter.remaining_mut(), 0);
474
475 assert_eq!(data[0], 0x11);
477 assert_eq!(data[1], 0x22);
478 assert_eq!(data[2], 0x33);
479 assert_eq!(data[3], 0x00); }
481
482 #[test]
483 fn test_putter_try_advance() {
484 let mut data = [0u8; 5];
485 let mut putter = Putter::new(&mut data[..]);
486
487 assert!(putter.try_advance_mut(2).is_ok());
488 assert_eq!(putter.position(), 2);
489
490 assert!(putter.try_advance_mut(5).is_err());
492 assert_eq!(putter.position(), 2); }
494
495 #[test]
496 #[should_panic(expected = "advance")]
497 fn test_putter_advance_panic() {
498 let mut data = [0u8; 3];
499 let mut putter = Putter::new(&mut data[..]);
500
501 putter.advance_mut(5); }
503
504 #[test]
505 fn test_putter_with_different_integer_types() {
506 let mut data = [0u8; 20];
507 let mut putter = Putter::new(&mut data[..]);
508
509 putter.write_u16_le(0x1234);
511 putter.write_u32_le(0x56789ABC);
512 assert_eq!(putter.position(), 6);
513
514 assert_eq!(&data[0..2], &[0x34, 0x12]); assert_eq!(&data[2..6], &[0xBC, 0x9A, 0x78, 0x56]); }
518
519 #[test]
520 fn test_putter_write_slice() {
521 let mut data = [0u8; 10];
522 let mut putter = Putter::new(&mut data[..]);
523
524 let test_data = [0x11, 0x22, 0x33, 0x44];
525 putter.write_slice(&test_data);
526
527 assert_eq!(putter.position(), 4);
528 assert_eq!(&data[0..4], &test_data);
529 assert_eq!(data[4], 0x00); }
531
532 #[test]
533 fn test_putter_with_advanced_buffer() {
534 let mut data = [0u8; 10];
535 let mut buf = &mut data[..];
536
537 buf.advance_mut(3);
539 assert_eq!(buf.remaining_mut(), 7);
540
541 let mut putter = Putter::new(buf);
543 assert_eq!(putter.remaining_mut(), 7);
544 putter.put_u8(0x42);
545
546 drop(putter);
547
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 drop(putter);
613
614 assert_eq!(data, [0x11, 0x22, 0x33]);
616 }
617
618 #[test]
619 fn test_putter_from_trait() {
620 let mut data = [0u8; 10];
621
622 let putter: Putter<_> = (&mut data[..]).into();
624 assert_eq!(putter.remaining_mut(), 10);
625 }
626
627 #[test]
628 fn test_putter_endianness() {
629 let mut data = [0u8; 16];
630 let mut putter = Putter::new(&mut data[..]);
631
632 putter.write_u16_le(0x1234);
634 putter.write_u16_be(0x1234);
635 putter.write_u32_le(0x12345678);
636 putter.write_u32_be(0x12345678);
637
638 assert_eq!(&data[0..2], &[0x34, 0x12]);
640 assert_eq!(&data[2..4], &[0x12, 0x34]);
642 assert_eq!(&data[4..8], &[0x78, 0x56, 0x34, 0x12]);
644 assert_eq!(&data[8..12], &[0x12, 0x34, 0x56, 0x78]);
646 }
647
648 #[test]
649 fn test_putter_signed_values() {
650 let mut data = [0u8; 10];
651 let mut putter = Putter::new(&mut data[..]);
652
653 putter.write_i8(-1);
655 putter.write_i16_le(-1);
656 putter.write_i32_be(-1);
657
658 assert_eq!(data[0], 0xFF);
660 assert_eq!(&data[1..3], &[0xFF, 0xFF]);
662 assert_eq!(&data[3..7], &[0xFF, 0xFF, 0xFF, 0xFF]);
664 }
665
666 #[test]
667 fn test_putter_reset_position_preserves_limits() {
668 let mut data = [0u8; 10];
669 let mut putter = Putter::with_limit(&mut data[..], 5);
670
671 putter.advance_mut(3);
672 assert_eq!(putter.position(), 3);
673 assert_eq!(putter.remaining_mut(), 2);
674
675 putter.reset_position();
676 assert_eq!(putter.position(), 0);
677 assert_eq!(putter.remaining_mut(), 5); }
679
680 #[test]
681 fn test_putter_truncate_after_advance() {
682 let mut data = [0u8; 10];
683 let mut putter = Putter::new(&mut data[..]);
684
685 putter.advance_mut(3);
686 assert_eq!(putter.remaining_mut(), 7);
687
688 putter.truncate_mut(4);
689 assert_eq!(putter.remaining_mut(), 4);
690
691 putter.write_slice(&[0x11, 0x22, 0x33, 0x44]);
693 assert_eq!(putter.remaining_mut(), 0);
694
695 assert_eq!(&data[3..7], &[0x11, 0x22, 0x33, 0x44]);
697 }
698
699 #[test]
700 fn test_putter_truncate_limited_putter() {
701 let mut data = [0u8; 10];
702 let mut putter = Putter::with_limit(&mut data[..], 6);
703
704 assert_eq!(putter.remaining_mut(), 6);
705
706 putter.truncate_mut(4);
708 assert_eq!(putter.remaining_mut(), 4);
709
710 putter.truncate_mut(2);
712 assert_eq!(putter.remaining_mut(), 2);
713 }
714
715 #[test]
716 fn test_error_details() {
717 let mut data = [0u8; 3];
718 let mut putter = Putter::new(&mut data[..]);
719
720 let advance_err = putter.try_advance_mut(5).unwrap_err();
722 assert_eq!(advance_err.requested(), 5);
723 assert_eq!(advance_err.available(), 3);
724 }
725
726 #[test]
727 fn test_putter_large_data() {
728 let mut large_data = [0u8; 1000];
730 let mut putter = Putter::new(&mut large_data[..]);
731
732 assert_eq!(putter.remaining_mut(), 1000);
733
734 for i in 0..100 {
736 putter.write_u8(i as u8);
737 }
738
739 assert_eq!(putter.remaining_mut(), 900);
740 assert_eq!(putter.position(), 100);
741
742 for i in 0..100 {
744 assert_eq!(large_data[i], i as u8);
745 }
746 }
747
748 #[test]
749 fn test_putter_boundary_conditions() {
750 let mut single_byte = [0u8; 1];
752 let mut putter = Putter::new(&mut single_byte[..]);
753
754 assert_eq!(putter.remaining_mut(), 1);
755 putter.write_u8(0x42);
756 assert_eq!(putter.remaining_mut(), 0);
757
758 assert!(putter.try_advance_mut(1).is_err());
760 assert_eq!(putter.put_u8_checked(0x99), None);
761 assert!(putter.try_put_u8(0x99).is_err());
762
763 putter.reset_position();
765 assert_eq!(putter.remaining_mut(), 1);
766 }
767
768 #[test]
769 fn test_putter_with_limit_larger_than_buffer() {
770 let mut data = [0u8; 3];
771 let putter = Putter::with_limit(&mut data[..], 10);
772
773 assert_eq!(putter.remaining_mut(), 3);
775 }
776
777 #[test]
778 fn test_putter_with_limit_zero() {
779 let mut data = [0u8; 5];
780 let putter = Putter::with_limit(&mut data[..], 0);
781
782 assert_eq!(putter.remaining_mut(), 0);
783 }
784
785 #[test]
786 fn test_written_calculation() {
787 let mut data = [0u8; 10];
788 let mut putter = Putter::new(&mut data[..]);
789
790 assert_eq!(putter.position(), 0);
792
793 putter.advance_mut(2);
794 assert_eq!(putter.position(), 2);
795
796 putter.write_u8(0x42);
797 assert_eq!(putter.position(), 3);
798
799 putter.write_slice(&[1, 2, 3]);
800 assert_eq!(putter.position(), 6);
801
802 putter.reset_position();
804 assert_eq!(putter.position(), 0);
805 }
806
807 #[test]
808 fn test_putter_ergonomic_comparison() {
809 let mut data = [0u8; 10];
810
811 let mut putter = Putter::new(&mut data[..]); putter.write_u8(0x42);
819 assert_eq!(putter.position(), 1);
820
821 drop(putter);
822 assert_eq!(data[0], 0x42);
823 }
824
825 #[test]
826 fn test_putter_with_range() {
827 let mut data = [0u8; 10];
828 let mut putter = Putter::with_range(&mut data[..], 2..=8);
829
830 assert_eq!(putter.remaining_mut(), 7);
831
832 putter.write_u8(0x42);
833 assert_eq!(putter.position(), 1);
834 putter.reset();
835 drop(putter);
836 assert_eq!(data[2], 0);
837
838 let mut putter = Putter::with_range(&mut data[..], ..7);
839 assert_eq!(putter.remaining_mut(), 7);
840 putter.write_u8(0x99);
841 assert_eq!(putter.position(), 1);
842 putter.reset();
843 drop(putter);
844 assert_eq!(data[0], 0);
845
846 let mut putter = Putter::with_range(&mut data[..], (Bound::Excluded(1), Bound::Unbounded));
847 assert_eq!(putter.remaining_mut(), 8);
848 putter.write_u8(0x77);
849 assert_eq!(putter.position(), 1);
850 putter.reset();
851 drop(putter);
852 assert_eq!(data[2], 0);
853 }
854}