pub mod common;
#[global_allocator]
static ALLOCATOR: Tracker = Tracker;
use std::{cell::Cell, num::NonZero};
use common::{
alloc::system::{Activity, Tracker},
buffer::{Counted, domain::Capacity, try_item},
};
use o3::buffer::{
self, Residency as _,
hold::{self, Charge, Overflow, ranges},
segments, storage,
write::consume::scope,
};
#[test]
fn validates_at_source() {
use hold::scope::Input;
let source = Counted {
bytes: *b"abc",
reads: Cell::new(Some(0)),
};
Capacity(0)
.try_scope(|budget| {
let input = Input::new(&source, &budget);
let result = input.try_plan(0..4);
let error = result.err().expect("the observed range exceeds the source");
assert_eq!((error.start(), error.end(), error.len()), (0, 4, 3));
assert_eq!(source.reads.get(), Some(1));
let plan = (input.try_plan(0..3)).expect("the complete source must be admitted");
assert_eq!(source.reads.get(), Some(2));
assert_eq!(plan.as_slice(), b"abc");
assert_eq!(plan.as_slice().as_ptr(), source.bytes.as_ptr());
assert_eq!(source.reads.get(), Some(2));
let (split, activity) = Tracker::activity(|| plan.try_split::<2>());
assert!(activity == Activity::default());
let (head, tail) = (split).expect("the two-byte header fits");
assert_eq!(head, b"ab");
assert_eq!(head.as_ptr(), source.bytes.as_ptr());
assert_eq!(tail.as_slice(), b"c");
let result = tail.try_split::<2>();
let cause = result
.err()
.expect("the one-byte remainder cannot contain two bytes");
assert_eq!(
cause.into_parts(),
(NonZero::<usize>::MIN.saturating_add(1), 1)
);
assert_eq!(
head, b"ab",
"the original borrow outlives the consumed plan"
);
assert_eq!(source.reads.get(), Some(2));
input.scope(|input| {
let count = NonZero::<usize>::MIN.saturating_add(2);
assert!(matches!(
input.try_prefix::<2>(usize::MAX, count),
Err(scope::Error::Maximum { count: observed, maximum: 2 }) if observed == count
));
let error = input
.try_prefix::<3>(4, count)
.err()
.expect("the payload range is reversed");
assert!(matches!(error, scope::Error::Range(error)
if (error.start(), error.end(), error.len()) == (4, 3, 3)));
assert_eq!(source.reads.get(), Some(3));
let (payload, end) = input.try_prefix::<3>(1, count).expect("payload fits");
assert_eq!(payload.as_slice(), b"bc");
assert_eq!(
payload.as_slice().as_ptr(),
source.bytes.as_ptr().wrapping_add(1)
);
assert_eq!(end.count().get(), 3);
});
assert_eq!(source.reads.get(), Some(4));
})
.expect("resident test domain must admit its budget");
}
#[test]
fn prefix_borrows_source() {
let source = (storage::Shared::try_copy(b"abcdef")).expect("source allocation");
let (prefix, activity) = Tracker::activity(|| {
scope::Input::new(&source).scope(|input| {
let count = NonZero::<usize>::MIN.saturating_add(2);
input
.try_prefix::<{ u32::MAX }>(0, count)
.map(|(prefix, end)| {
assert_eq!(end.count().get() as usize, count.get());
prefix
})
})
});
assert!(activity == Activity::default());
let prefix = (prefix).expect("the prefix fits its source");
assert_eq!(prefix.as_slice(), b"abc");
assert_eq!(prefix.as_slice().as_ptr(), source.as_ptr());
assert_eq!(source.as_slice(), b"abcdef");
}
#[test]
fn consume_own_prefix() {
let mut source = (storage::Shared::try_copy(b"abcdef")).expect("source allocation");
let start = source.as_ptr();
let (result, activity) = Tracker::activity(|| {
scope::Input::consume(&mut source, |input| {
match input.try_prefix::<6>(1, NonZero::<usize>::MIN.saturating_add(2)) {
Ok((prefix, end)) => {
assert_eq!(prefix.as_slice(), b"bc");
(Some(end), Ok(()))
}
Err(error) => (None, Err(error)),
}
})
});
result.as_ref().expect("required fixture outcome");
assert!(activity == Activity::default());
assert_eq!(source.as_slice(), b"def");
assert_eq!(source.as_ptr(), start.wrapping_add(3));
scope::Input::consume::<_, 6>(&mut source, |input| {
let admitted = input.try_prefix::<6>(0, NonZero::<usize>::MIN);
admitted.as_ref().expect("required fixture outcome");
(None, ())
});
assert_eq!(source.as_slice(), b"def");
let rejected = scope::Input::consume::<_, 6>(&mut source, |input| {
match input.try_prefix::<6>(0, NonZero::<usize>::MIN.saturating_add(3)) {
Err(error) => (None, Some(error)),
Ok(_) => (None, None),
}
});
assert!(matches!(rejected, Some(scope::Error::Range(error))
if (error.start(), error.end(), error.len()) == (0, 4, 3)));
assert_eq!(source.as_slice(), b"def");
}
#[test]
fn commit_or_cancel_pooled() {
use buffer::{Cursor as _, bytes, pool, write::consume::Consume as _};
let pool = (pool::Pool::try_new(1, 16)).expect("pooled source allocation");
let mut writer = (pool.view()).expect("one free pooled slot");
{
let mut spare = writer.spare();
assert_eq!(spare.write(b"abcdef"), 6);
spare.commit();
}
let mut source = writer.freeze();
let ((), activity) = Tracker::activity(|| {
for commit in [false, true] {
let mut cursor = bytes::Cursor::new(&mut source);
scope::Input::consume(&mut cursor, |input| {
let (prefix, end) = (input
.try_prefix::<6>(0, NonZero::<usize>::MIN.saturating_add(1)))
.expect("the first two bytes fit");
assert_eq!(prefix.as_slice(), b"ab");
(Some(end), ())
});
let plan = cursor.try_get(0..4).expect("the remaining four bytes fit");
assert_eq!(plan.as_slice(), b"cdef");
if commit {
assert_eq!(cursor.commit(), 2);
}
}
assert_eq!(source.as_slice(), b"cdef");
let mut cursor = bytes::Cursor::new(&mut source);
cursor.consume_max(usize::MAX);
assert_eq!(cursor.commit(), 4);
});
assert!(activity == Activity::default());
assert!(pool.view().is_some());
}
#[test]
fn consume_keeps_source() {
use buffer::write::consume::Consume as _;
let source = storage::Shared::try_copy(b"abcdef").expect("shared source allocation");
let mut view = buffer::View::new(&source)
.try_get(1..5)
.expect("the middle four bytes fit");
let ((), activity) = Tracker::activity(|| {
view.try_consume(1)
.expect("one byte fits the selected view");
let result = view.try_consume(usize::MAX);
let error = result.expect_err("an oversized consume preserves the selected suffix");
let (required, left) = error.into_parts();
assert_eq!((required.get(), left), (usize::MAX, 3));
assert_eq!(view.as_slice(), b"cde");
assert_eq!(view.as_slice().as_ptr(), source.as_slice()[2..].as_ptr());
view.try_consume(0).expect("an empty prefix always fits");
assert_eq!(view.consume_max(usize::MAX), 3);
view.try_consume(0)
.expect("an empty view admits an empty prefix");
assert!(view.is_empty());
});
assert!(activity == Activity::default());
assert_eq!(source.as_slice(), b"abcdef");
}
#[test]
fn reports_overflow() {
let logical = Charge::from_commit(usize::MAX, 3, 5);
assert!(
logical.try_add(Charge::from_commit(1, 7, 11))
== Err(Overflow::Logical {
left: usize::MAX,
right: 1,
})
);
let resident = Charge::from_commit(2, usize::MAX, 5);
assert!(
resident.try_add(Charge::from_commit(3, 1, 11))
== Err(Overflow::Resident {
left: usize::MAX,
right: 1,
})
);
let owners = Charge::from_commit(2, 3, usize::MAX);
assert!(
owners.try_add(Charge::from_commit(5, 7, 1))
== Err(Overflow::Owners {
left: usize::MAX,
right: 1,
})
);
}
#[test]
fn projects_retained() {
let owned = try_item(b"owned").expect("the retained chain fixture must allocate");
let resident = owned.resident();
let retained = segments::Item::from(owned.try_clone().expect("retained alias"));
let borrowed = segments::Item::from(b"borrowed");
let owned = segments::Item::from(owned);
let chain = (segments::Many::try_from((owned, borrowed))).expect("segment transition accepted");
let chain = segments::Many::try_from((chain, retained)).expect("retained owner appended");
assert!(Charge::from(chain.as_chain()) == Charge::from_commit(10, resident * 2, 2));
}
#[test]
fn retains_after_plans() {
let (direct, iterated) = {
let source = storage::Shared::try_copy(b"_ab__cde_").expect("source allocation");
let ((direct, iterated, slice), activity) = Tracker::measure(|| {
let spans = [(1u32, 3), (5, 8)];
let plan = unsafe { ranges::Set::from_parts(&source, &spans, 5) };
let direct = plan.get(1).expect("second range");
let iterated = plan.iter().next().expect("first range");
let span = [(1, 3)];
let single = ranges::Set::<_>::try_new(&source, &span, 2).expect("contiguous range");
(direct, iterated, single.contiguous().expect("one range"))
});
assert_eq!(activity, [0; 4]);
assert_eq!(direct.as_slice(), b"cde");
assert_eq!(iterated.as_slice(), b"ab");
assert_eq!(slice, b"ab");
assert_eq!(direct.as_slice().as_ptr(), source.as_slice()[5..].as_ptr());
assert_eq!(
iterated.as_slice().as_ptr(),
source.as_slice()[1..].as_ptr()
);
assert_eq!(slice.as_ptr(), source.as_slice()[1..].as_ptr());
let ((direct, iterated), activity) = Tracker::measure(|| {
(
direct.try_retain().expect("selected owner"),
iterated.try_retain().expect("iterated owner"),
)
});
assert_eq!(activity, [0; 4]);
(direct, iterated)
};
assert_eq!(direct.as_slice(), b"cde");
assert_eq!(iterated.as_slice(), b"ab");
}