use super::Buf;
#[derive(Debug)]
pub struct Chain<T, U> {
a: T,
b: U,
}
impl<T, U> Chain<T, U> {
#[inline]
pub(crate) fn new(a: T, b: U) -> Self {
Self { a, b }
}
#[inline]
#[must_use]
pub fn first_ref(&self) -> &T {
&self.a
}
#[inline]
pub fn first_mut(&mut self) -> &mut T {
&mut self.a
}
#[inline]
#[must_use]
pub fn last_ref(&self) -> &U {
&self.b
}
#[inline]
pub fn last_mut(&mut self) -> &mut U {
&mut self.b
}
#[inline]
#[must_use]
pub fn into_inner(self) -> (T, U) {
(self.a, self.b)
}
}
impl<T: Buf, U: Buf> Buf for Chain<T, U> {
#[inline]
fn remaining(&self) -> usize {
self.a.remaining().saturating_add(self.b.remaining())
}
#[inline]
fn chunk(&self) -> &[u8] {
if self.a.has_remaining() {
self.a.chunk()
} else {
self.b.chunk()
}
}
#[inline]
fn advance(&mut self, mut cnt: usize) {
let a_rem = self.a.remaining();
if cnt <= a_rem {
self.a.advance(cnt);
} else {
if a_rem > 0 {
self.a.advance(a_rem);
}
cnt -= a_rem;
self.b.advance(cnt);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn init_test(name: &str) {
crate::test_utils::init_test_logging();
crate::test_phase!(name);
}
#[test]
fn test_chain_remaining() {
init_test("test_chain_remaining");
let a: &[u8] = &[1, 2, 3];
let b: &[u8] = &[4, 5, 6];
let chain = Chain::new(a, b);
let remaining = chain.remaining();
crate::assert_with_log!(remaining == 6, "remaining", 6, remaining);
crate::test_complete!("test_chain_remaining");
}
#[test]
fn test_chain_chunk() {
init_test("test_chain_chunk");
let a: &[u8] = &[1, 2, 3];
let b: &[u8] = &[4, 5, 6];
let chain = Chain::new(a, b);
let chunk = chain.chunk();
crate::assert_with_log!(chunk == [1, 2, 3], "chunk", &[1, 2, 3], chunk);
crate::test_complete!("test_chain_chunk");
}
#[test]
fn test_chain_advance() {
init_test("test_chain_advance");
let a: &[u8] = &[1, 2, 3];
let b: &[u8] = &[4, 5, 6];
let mut chain = Chain::new(a, b);
chain.advance(2);
let remaining = chain.remaining();
crate::assert_with_log!(remaining == 4, "remaining", 4, remaining);
let chunk = chain.chunk();
crate::assert_with_log!(chunk == [3], "chunk", &[3], chunk);
chain.advance(1);
let remaining = chain.remaining();
crate::assert_with_log!(remaining == 3, "remaining", 3, remaining);
let chunk = chain.chunk();
crate::assert_with_log!(chunk == [4, 5, 6], "chunk", &[4, 5, 6], chunk);
chain.advance(2);
let remaining = chain.remaining();
crate::assert_with_log!(remaining == 1, "remaining", 1, remaining);
let chunk = chain.chunk();
crate::assert_with_log!(chunk == [6], "chunk", &[6], chunk);
crate::test_complete!("test_chain_advance");
}
#[test]
fn test_chain_copy_to_slice() {
init_test("test_chain_copy_to_slice");
let a: &[u8] = &[1, 2, 3];
let b: &[u8] = &[4, 5, 6];
let mut chain = Chain::new(a, b);
let mut dst = [0u8; 6];
chain.copy_to_slice(&mut dst);
let ok = dst == [1, 2, 3, 4, 5, 6];
crate::assert_with_log!(ok, "dst", [1, 2, 3, 4, 5, 6], dst);
crate::test_complete!("test_chain_copy_to_slice");
}
#[test]
fn test_chain_getters() {
init_test("test_chain_getters");
let a: &[u8] = &[1, 2, 3];
let b: &[u8] = &[4, 5, 6];
let mut chain = Chain::new(a, b);
let first = *chain.first_ref();
crate::assert_with_log!(first == &[1, 2, 3][..], "first", &[1, 2, 3][..], first);
let last = *chain.last_ref();
crate::assert_with_log!(last == &[4, 5, 6][..], "last", &[4, 5, 6][..], last);
chain.advance(4);
let first = *chain.first_ref();
crate::assert_with_log!(first == b"", "first", b"", first);
let last = *chain.last_ref();
crate::assert_with_log!(last == &[5, 6][..], "last", &[5, 6][..], last);
crate::test_complete!("test_chain_getters");
}
#[test]
fn test_chain_into_inner() {
init_test("test_chain_into_inner");
let a: &[u8] = &[1, 2, 3];
let b: &[u8] = &[4, 5, 6];
let chain = Chain::new(a, b);
let (a_out, b_out) = chain.into_inner();
let ok = a_out == [1, 2, 3];
crate::assert_with_log!(ok, "a_out", &[1, 2, 3], a_out);
let ok = b_out == [4, 5, 6];
crate::assert_with_log!(ok, "b_out", &[4, 5, 6], b_out);
crate::test_complete!("test_chain_into_inner");
}
}