1use core::ops::{Bound, RangeBounds};
2
3use crate::error::TryAdvanceError;
4
5use super::{BufMut, WriteBuf};
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: WriteBuf<B>,
47}
48
49impl<B: BufMut> 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<WriteBuf<B>>) -> Self
73 where
74 B: BufMut,
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 Self::with_cursor_and_bounds_inner(WriteBuf::new(buf), 0, Bound::Included(0), Bound::Unbounded)
97 }
98
99 #[inline]
114 pub fn with_limit(buf: impl Into<WriteBuf<B>>, limit: usize) -> Self {
115 let write_buf = buf.into();
116 Self::with_cursor_and_bounds_inner(write_buf, 0, Bound::Included(0), Bound::Excluded(limit))
117 }
118
119 #[inline]
134 pub const fn const_with_limit(buf: WriteBuf<B>, limit: usize) -> Self {
135 Self::with_cursor_and_bounds_inner(buf, 0, Bound::Included(0), Bound::Excluded(limit))
136 }
137
138 #[inline]
156 pub fn with_range(buf: impl Into<WriteBuf<B>>, range: impl RangeBounds<usize>) -> Self
157 where
158 B: BufMut,
159 {
160 let start = range.start_bound().cloned();
161 let end = range.end_bound().cloned();
162 let write_buf = buf.into();
163 let start_pos = Self::resolve_start_bound(start, &write_buf);
164 Self::with_cursor_and_bounds_inner(write_buf, start_pos, Bound::Included(start_pos), end)
165 }
166
167 #[inline]
186 pub const fn position(&self) -> usize {
187 let start_pos = Self::resolve_start_bound_without_check(self.start);
188 self.cursor.saturating_sub(start_pos)
189 }
190
191 #[inline]
209 pub const fn absolute_position(&self) -> usize {
210 self.cursor
211 }
212
213 #[inline]
237 pub const fn reset_position(&mut self) {
238 self.cursor = Self::resolve_start_bound_without_check(self.start);
239 self.limit = self.end;
240 }
241
242 pub fn reset(&mut self)
262 where
263 B: BufMut,
264 {
265 self.reset_position();
266 self.fill(0);
267 }
268
269 #[inline]
286 pub fn into_inner(self) -> B {
287 self.buf.0
288 }
289
290 #[inline]
291 const fn with_cursor_and_bounds_inner(
292 buf: WriteBuf<B>,
293 cursor: usize,
294 start: Bound<usize>,
295 end: Bound<usize>,
296 ) -> Self {
297 Self {
298 buf,
299 cursor,
300 start,
301 end,
302 limit: end,
303 }
304 }
305
306 #[inline]
307 const fn resolve_start_bound_without_check(bound: Bound<usize>) -> usize {
308 match bound {
309 Bound::Included(n) => n,
310 Bound::Excluded(n) => n.saturating_add(1),
311 Bound::Unbounded => 0,
312 }
313 }
314}
315
316impl<B: ?Sized> Putter<B> {
317 #[inline]
318 fn resolve_start_bound(bound: Bound<usize>, buf: &WriteBuf<B>) -> usize
319 where
320 B: BufMut,
321 {
322 let pos = match bound {
323 Bound::Included(n) => n,
324 Bound::Excluded(n) => n.saturating_add(1),
325 Bound::Unbounded => 0,
326 };
327 pos.min(buf.remaining_mut())
328 }
329
330 #[inline]
331 fn resolve_end_bound(&self, bound: Bound<usize>) -> usize
332 where
333 B: BufMut,
334 {
335 match bound {
336 Bound::Included(n) => (n.saturating_add(1)).min(self.buf.remaining_mut()),
337 Bound::Excluded(n) => n.min(self.buf.remaining_mut()),
338 Bound::Unbounded => self.buf.remaining_mut(),
339 }
340 }
341}
342
343impl<B: BufMut + ?Sized> BufMut for Putter<B> {
344 #[inline]
345 fn remaining_mut(&self) -> usize {
346 let end_pos = self.resolve_end_bound(self.limit);
347 end_pos.saturating_sub(self.cursor)
348 }
349
350 #[inline]
351 fn buffer_mut(&mut self) -> &mut [u8] {
352 let start = self.cursor.min(self.buf.remaining_mut());
353 let end_pos = self.resolve_end_bound(self.limit);
354 &mut self.buf.buffer_mut()[start..end_pos]
355 }
356
357 #[inline]
358 fn advance_mut(&mut self, cnt: usize) {
359 let remaining = self.remaining_mut();
360 if cnt > remaining {
361 super::panic_advance(&TryAdvanceError::new(cnt, remaining));
362 }
363 self.cursor += cnt;
364 }
365
366 #[inline]
367 fn try_advance_mut(&mut self, cnt: usize) -> Result<(), TryAdvanceError> {
368 let remaining = self.remaining_mut();
369 if cnt > remaining {
370 return Err(TryAdvanceError::new(cnt, remaining));
371 }
372 self.cursor += cnt;
373 Ok(())
374 }
375
376 #[inline]
377 fn truncate_mut(&mut self, new_len: usize) {
378 let current_remaining = self.remaining_mut();
379 if new_len >= current_remaining {
380 return; }
382
383 let new_end_pos = self.cursor + new_len;
384 let current_end_pos = self.resolve_end_bound(self.limit);
385
386 if new_end_pos < current_end_pos {
388 self.limit = Bound::Excluded(new_end_pos);
389 }
390 }
391}
392
393#[cfg(test)]
394mod tests {
395 use super::*;
396
397 #[test]
398 fn test_putter_basic_functionality() {
399 let mut data = [0u8; 10];
400 let mut putter = Putter::new(&mut data[..]);
401
402 assert_eq!(putter.remaining_mut(), 10);
403 assert_eq!(putter.position(), 0);
404
405 putter.write_u8(0x42);
407 assert_eq!(putter.remaining_mut(), 9);
408 assert_eq!(putter.position(), 1);
409
410 assert_eq!(data[0], 0x42);
412 }
413
414 #[test]
415 fn test_putter_ergonomic_api() {
416 let mut data = [0u8; 10];
418 let mut putter = Putter::new(&mut data[..]); putter.put_u8(0x11);
421 assert_eq!(data[0], 0x11);
422 }
423
424 #[test]
425 fn test_putter_with_limit() {
426 let mut data = [0u8; 10];
427 let mut putter = Putter::with_limit(&mut data[..], 3);
428
429 assert_eq!(putter.remaining_mut(), 3);
430
431 putter.write_u8(0x11);
433 putter.write_u8(0x22);
434 putter.write_u8(0x33);
435
436 assert_eq!(putter.remaining_mut(), 0);
438
439 assert_eq!(data[0], 0x11);
441 assert_eq!(data[1], 0x22);
442 assert_eq!(data[2], 0x33);
443 assert_eq!(data[3], 0x00); }
445
446 #[test]
447 fn test_putter_reset_position() {
448 let mut data = [0u8; 10];
449 let mut putter = Putter::new(&mut data[..]);
450
451 putter.advance_mut(3);
452 assert_eq!(putter.position(), 3);
453 assert_eq!(putter.remaining_mut(), 7);
454
455 putter.reset_position();
456 assert_eq!(putter.position(), 0);
457 assert_eq!(putter.remaining_mut(), 10);
458 }
459
460 #[test]
461 fn test_putter_truncate() {
462 let mut data = [0u8; 10];
463 let mut putter = Putter::new(&mut data[..]);
464
465 putter.truncate_mut(3);
466 assert_eq!(putter.remaining_mut(), 3);
467
468 putter.write_u8(0x11);
470 putter.write_u8(0x22);
471 putter.write_u8(0x33);
472 assert_eq!(putter.remaining_mut(), 0);
473
474 assert_eq!(data[0], 0x11);
476 assert_eq!(data[1], 0x22);
477 assert_eq!(data[2], 0x33);
478 assert_eq!(data[3], 0x00); }
480
481 #[test]
482 fn test_putter_try_advance() {
483 let mut data = [0u8; 5];
484 let mut putter = Putter::new(&mut data[..]);
485
486 assert!(putter.try_advance_mut(2).is_ok());
487 assert_eq!(putter.position(), 2);
488
489 assert!(putter.try_advance_mut(5).is_err());
491 assert_eq!(putter.position(), 2); }
493
494 #[test]
495 #[should_panic(expected = "advance")]
496 fn test_putter_advance_panic() {
497 let mut data = [0u8; 3];
498 let mut putter = Putter::new(&mut data[..]);
499
500 putter.advance_mut(5); }
502
503 #[test]
504 fn test_putter_with_different_integer_types() {
505 let mut data = [0u8; 20];
506 let mut putter = Putter::new(&mut data[..]);
507
508 putter.write_u16_le(0x1234);
510 putter.write_u32_le(0x56789ABC);
511 assert_eq!(putter.position(), 6);
512
513 assert_eq!(&data[0..2], &[0x34, 0x12]); assert_eq!(&data[2..6], &[0xBC, 0x9A, 0x78, 0x56]); }
517
518 #[test]
519 fn test_putter_write_slice() {
520 let mut data = [0u8; 10];
521 let mut putter = Putter::new(&mut data[..]);
522
523 let test_data = [0x11, 0x22, 0x33, 0x44];
524 putter.write_slice(&test_data);
525
526 assert_eq!(putter.position(), 4);
527 assert_eq!(&data[0..4], &test_data);
528 assert_eq!(data[4], 0x00); }
530
531 #[test]
532 fn test_putter_with_advanced_buffer() {
533 let mut data = [0u8; 10];
534 let mut buf = &mut data[..];
535
536 buf.advance_mut(3);
538 assert_eq!(buf.remaining_mut(), 7);
539
540 let mut putter = Putter::new(buf);
542 assert_eq!(putter.remaining_mut(), 7);
543 putter.put_u8(0x42);
544
545 drop(putter);
546
547 assert_eq!(data[3], 0x42); }
550
551 #[test]
552 fn test_putter_buffer_mut_access() {
553 let mut data = [0u8; 10];
554 let mut putter = Putter::new(&mut data[..]);
555
556 putter.write_u8(0x11);
558 putter.write_u8(0x22);
559
560 let remaining_buffer = putter.buffer_mut();
562 remaining_buffer[0] = 0x99; assert_eq!(data[0], 0x11);
565 assert_eq!(data[1], 0x22);
566 assert_eq!(data[2], 0x99);
567 }
568
569 #[test]
570 fn test_putter_state_consistency() {
571 let mut data = [0u8; 10];
572 let mut putter = Putter::new(&mut data[..]);
573
574 let initial_remaining = putter.remaining_mut();
576 let initial_written = putter.position();
577
578 putter.advance_mut(3);
580 assert_eq!(
581 putter.remaining_mut() + putter.position(),
582 initial_remaining
583 );
584
585 putter.truncate_mut(5);
587 assert_eq!(putter.remaining_mut(), 5);
588 assert_eq!(putter.position(), 3);
589
590 putter.reset_position();
592 assert_eq!(putter.position(), initial_written);
593 assert_eq!(putter.remaining_mut(), initial_remaining); }
595
596 #[test]
597 fn test_putter_exhaustive_write() {
598 let mut data = [0u8; 3];
599 let mut putter = Putter::new(&mut data[..]);
600
601 assert_eq!(putter.write_u8(0x11), 1);
603 assert_eq!(putter.remaining_mut(), 2);
604
605 assert_eq!(putter.write_u8(0x22), 1);
606 assert_eq!(putter.remaining_mut(), 1);
607
608 assert_eq!(putter.write_u8(0x33), 1);
609 assert_eq!(putter.remaining_mut(), 0);
610
611 drop(putter);
612
613 assert_eq!(data, [0x11, 0x22, 0x33]);
615 }
616
617 #[test]
618 fn test_putter_from_trait() {
619 let mut data = [0u8; 10];
620
621 let putter: Putter<_> = (&mut data[..]).into();
623 assert_eq!(putter.remaining_mut(), 10);
624 }
625
626 #[test]
627 fn test_putter_endianness() {
628 let mut data = [0u8; 16];
629 let mut putter = Putter::new(&mut data[..]);
630
631 putter.write_u16_le(0x1234);
633 putter.write_u16_be(0x1234);
634 putter.write_u32_le(0x12345678);
635 putter.write_u32_be(0x12345678);
636
637 assert_eq!(&data[0..2], &[0x34, 0x12]);
639 assert_eq!(&data[2..4], &[0x12, 0x34]);
641 assert_eq!(&data[4..8], &[0x78, 0x56, 0x34, 0x12]);
643 assert_eq!(&data[8..12], &[0x12, 0x34, 0x56, 0x78]);
645 }
646
647 #[test]
648 fn test_putter_signed_values() {
649 let mut data = [0u8; 10];
650 let mut putter = Putter::new(&mut data[..]);
651
652 putter.write_i8(-1);
654 putter.write_i16_le(-1);
655 putter.write_i32_be(-1);
656
657 assert_eq!(data[0], 0xFF);
659 assert_eq!(&data[1..3], &[0xFF, 0xFF]);
661 assert_eq!(&data[3..7], &[0xFF, 0xFF, 0xFF, 0xFF]);
663 }
664
665 #[test]
666 fn test_putter_reset_position_preserves_limits() {
667 let mut data = [0u8; 10];
668 let mut putter = Putter::with_limit(&mut data[..], 5);
669
670 putter.advance_mut(3);
671 assert_eq!(putter.position(), 3);
672 assert_eq!(putter.remaining_mut(), 2);
673
674 putter.reset_position();
675 assert_eq!(putter.position(), 0);
676 assert_eq!(putter.remaining_mut(), 5); }
678
679 #[test]
680 fn test_putter_truncate_after_advance() {
681 let mut data = [0u8; 10];
682 let mut putter = Putter::new(&mut data[..]);
683
684 putter.advance_mut(3);
685 assert_eq!(putter.remaining_mut(), 7);
686
687 putter.truncate_mut(4);
688 assert_eq!(putter.remaining_mut(), 4);
689
690 putter.write_slice(&[0x11, 0x22, 0x33, 0x44]);
692 assert_eq!(putter.remaining_mut(), 0);
693
694 assert_eq!(&data[3..7], &[0x11, 0x22, 0x33, 0x44]);
696 }
697
698 #[test]
699 fn test_putter_truncate_limited_putter() {
700 let mut data = [0u8; 10];
701 let mut putter = Putter::with_limit(&mut data[..], 6);
702
703 assert_eq!(putter.remaining_mut(), 6);
704
705 putter.truncate_mut(4);
707 assert_eq!(putter.remaining_mut(), 4);
708
709 putter.truncate_mut(2);
711 assert_eq!(putter.remaining_mut(), 2);
712 }
713
714 #[test]
715 fn test_error_details() {
716 let mut data = [0u8; 3];
717 let mut putter = Putter::new(&mut data[..]);
718
719 let advance_err = putter.try_advance_mut(5).unwrap_err();
721 assert_eq!(advance_err.requested(), 5);
722 assert_eq!(advance_err.available(), 3);
723 }
724
725 #[test]
726 fn test_putter_large_data() {
727 let mut large_data = [0u8; 1000];
729 let mut putter = Putter::new(&mut large_data[..]);
730
731 assert_eq!(putter.remaining_mut(), 1000);
732
733 for i in 0..100 {
735 putter.write_u8(i as u8);
736 }
737
738 assert_eq!(putter.remaining_mut(), 900);
739 assert_eq!(putter.position(), 100);
740
741 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 drop(putter);
821 assert_eq!(data[0], 0x42);
822 }
823
824 #[test]
825 fn test_putter_with_range() {
826 let mut data = [0u8; 10];
827 let mut putter = Putter::with_range(&mut data[..], 2..=8);
828
829 assert_eq!(putter.remaining_mut(), 7);
830
831 putter.write_u8(0x42);
832 assert_eq!(putter.position(), 1);
833 putter.reset();
834 drop(putter);
835 assert_eq!(data[2], 0);
836
837 let mut putter = Putter::with_range(&mut data[..], ..7);
838 assert_eq!(putter.remaining_mut(), 7);
839 putter.write_u8(0x99);
840 assert_eq!(putter.position(), 1);
841 putter.reset();
842 drop(putter);
843 assert_eq!(data[0], 0);
844
845 let mut putter = Putter::with_range(&mut data[..], (Bound::Excluded(1), Bound::Unbounded));
846 assert_eq!(putter.remaining_mut(), 8);
847 putter.write_u8(0x77);
848 assert_eq!(putter.position(), 1);
849 putter.reset();
850 drop(putter);
851 assert_eq!(data[2], 0);
852 }
853}