Skip to main content

oxihuman_core/
copy_buffer.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5//! Fixed-capacity byte buffer with copy-in / copy-out semantics.
6
7/// A fixed-capacity byte buffer supporting copy-in and copy-out operations.
8#[allow(dead_code)]
9#[derive(Debug, Clone)]
10pub struct CopyBuffer {
11    data: Vec<u8>,
12    capacity: usize,
13}
14
15#[allow(dead_code)]
16impl CopyBuffer {
17    pub fn new(capacity: usize) -> Self {
18        Self {
19            data: Vec::with_capacity(capacity),
20            capacity,
21        }
22    }
23
24    pub fn capacity(&self) -> usize {
25        self.capacity
26    }
27
28    pub fn len(&self) -> usize {
29        self.data.len()
30    }
31
32    pub fn is_empty(&self) -> bool {
33        self.data.is_empty()
34    }
35
36    pub fn remaining(&self) -> usize {
37        self.capacity.saturating_sub(self.data.len())
38    }
39
40    /// Copy bytes in. Returns number of bytes actually written.
41    pub fn copy_in(&mut self, src: &[u8]) -> usize {
42        let avail = self.remaining();
43        let n = src.len().min(avail);
44        self.data.extend_from_slice(&src[..n]);
45        n
46    }
47
48    /// Copy out up to `n` bytes from the front. Returns the slice.
49    pub fn copy_out(&mut self, n: usize) -> Vec<u8> {
50        let take = n.min(self.data.len());
51        let out: Vec<u8> = self.data.drain(..take).collect();
52        out
53    }
54
55    /// Peek at up to `n` bytes without consuming them.
56    pub fn peek(&self, n: usize) -> &[u8] {
57        let take = n.min(self.data.len());
58        &self.data[..take]
59    }
60
61    pub fn clear(&mut self) {
62        self.data.clear();
63    }
64
65    pub fn as_slice(&self) -> &[u8] {
66        &self.data
67    }
68
69    /// True if capacity is reached.
70    pub fn is_full(&self) -> bool {
71        self.data.len() >= self.capacity
72    }
73
74    /// Fill with a repeated byte value.
75    pub fn fill(&mut self, byte: u8) {
76        let n = self.remaining();
77        for _ in 0..n {
78            self.data.push(byte);
79        }
80    }
81
82    /// Overwrite byte at position; returns false if out of range.
83    pub fn set_byte(&mut self, pos: usize, byte: u8) -> bool {
84        if pos < self.data.len() {
85            self.data[pos] = byte;
86            true
87        } else {
88            false
89        }
90    }
91
92    pub fn get_byte(&self, pos: usize) -> Option<u8> {
93        self.data.get(pos).copied()
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100
101    #[test]
102    fn new_empty() {
103        let buf = CopyBuffer::new(64);
104        assert!(buf.is_empty());
105        assert_eq!(buf.capacity(), 64);
106        assert_eq!(buf.remaining(), 64);
107    }
108
109    #[test]
110    fn copy_in_basic() {
111        let mut buf = CopyBuffer::new(8);
112        let n = buf.copy_in(&[1, 2, 3, 4]);
113        assert_eq!(n, 4);
114        assert_eq!(buf.len(), 4);
115    }
116
117    #[test]
118    fn copy_in_clamped_to_capacity() {
119        let mut buf = CopyBuffer::new(4);
120        let n = buf.copy_in(&[0u8; 10]);
121        assert_eq!(n, 4);
122        assert!(buf.is_full());
123    }
124
125    #[test]
126    fn copy_out_removes_front() {
127        let mut buf = CopyBuffer::new(16);
128        buf.copy_in(&[10, 20, 30, 40]);
129        let out = buf.copy_out(2);
130        assert_eq!(out, vec![10, 20]);
131        assert_eq!(buf.len(), 2);
132    }
133
134    #[test]
135    fn peek_does_not_consume() {
136        let mut buf = CopyBuffer::new(16);
137        buf.copy_in(&[1, 2, 3]);
138        let peeked = buf.peek(2);
139        assert_eq!(peeked, &[1, 2]);
140        assert_eq!(buf.len(), 3);
141    }
142
143    #[test]
144    fn fill_to_capacity() {
145        let mut buf = CopyBuffer::new(4);
146        buf.fill(0xFF);
147        assert!(buf.is_full());
148        assert_eq!(buf.as_slice(), &[0xFF, 0xFF, 0xFF, 0xFF]);
149    }
150
151    #[test]
152    fn set_and_get_byte() {
153        let mut buf = CopyBuffer::new(8);
154        buf.copy_in(&[0u8; 4]);
155        assert!(buf.set_byte(2, 99));
156        assert_eq!(buf.get_byte(2), Some(99));
157        assert!(!buf.set_byte(100, 0));
158    }
159
160    #[test]
161    fn clear_resets() {
162        let mut buf = CopyBuffer::new(8);
163        buf.copy_in(&[1, 2, 3]);
164        buf.clear();
165        assert!(buf.is_empty());
166        assert_eq!(buf.remaining(), 8);
167    }
168
169    #[test]
170    fn remaining_decreases() {
171        let mut buf = CopyBuffer::new(10);
172        buf.copy_in(&[0u8; 7]);
173        assert_eq!(buf.remaining(), 3);
174    }
175
176    #[test]
177    fn copy_out_partial_when_short() {
178        let mut buf = CopyBuffer::new(8);
179        buf.copy_in(&[5, 6]);
180        let out = buf.copy_out(10);
181        assert_eq!(out, vec![5, 6]);
182        assert!(buf.is_empty());
183    }
184}