Skip to content

Commit eaa5ccd

Browse files
test: proptest ByteArea layout
1 parent 3e12496 commit eaa5ccd

File tree

3 files changed

+109
-0
lines changed

3 files changed

+109
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
- removed the old `ByteBuffer` type in favor of `ByteArea`
2020
- added tests covering `ByteArea` sections, typed reserves and persistence
2121
- added test verifying alignment padding between differently aligned writes
22+
- added property tests generating random `ByteArea` sections and documented
23+
multi-typed section layouts
2224
- split Kani verification into `verify.sh` and streamline `preflight.sh`
2325
- clarify that `verify.sh` runs on a dedicated system and document avoiding async code
2426
- install `rustfmt` and the Kani verifier automatically via `cargo install`

src/area.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,38 @@
1313
//! lifetime. Multiple sections may coexist; their byte ranges do not overlap.
1414
//! Freezing a section via [`Section::freeze`] remaps its range as immutable and
1515
//! returns [`Bytes`].
16+
//!
17+
//! # Examples
18+
//!
19+
//! ```
20+
//! # #[cfg(all(feature = "mmap", feature = "zerocopy"))]
21+
//! # {
22+
//! use anybytes::area::ByteArea;
23+
//!
24+
//! let mut area = ByteArea::new().unwrap();
25+
//! let mut sections = area.sections();
26+
//!
27+
//! let mut a = sections.reserve::<u8>(1).unwrap();
28+
//! a.as_mut_slice()[0] = 1;
29+
//!
30+
//! let mut b = sections.reserve::<u32>(1).unwrap();
31+
//! b.as_mut_slice()[0] = 2;
32+
//!
33+
//! let bytes_a = a.freeze().unwrap();
34+
//! let bytes_b = b.freeze().unwrap();
35+
//! drop(sections);
36+
//! let all = area.freeze().unwrap();
37+
//!
38+
//! assert_eq!(bytes_a.as_ref(), &[1]);
39+
//! assert_eq!(bytes_b.as_ref(), &2u32.to_ne_bytes());
40+
//!
41+
//! let mut expected = Vec::new();
42+
//! expected.extend_from_slice(&[1]);
43+
//! expected.extend_from_slice(&[0; 3]);
44+
//! expected.extend_from_slice(&2u32.to_ne_bytes());
45+
//! assert_eq!(all.as_ref(), expected.as_slice());
46+
//! # }
47+
//! ```
1648
1749
use std::io::{self, Seek, SeekFrom};
1850
use std::marker::PhantomData;

tests/area.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#![cfg(all(feature = "mmap", feature = "zerocopy"))]
2+
3+
use anybytes::area::ByteArea;
4+
use proptest::prelude::*;
5+
6+
fn align_up(val: usize, align: usize) -> usize {
7+
(val + align - 1) & !(align - 1)
8+
}
9+
10+
#[derive(Debug, Clone)]
11+
enum Segment {
12+
U8(Vec<u8>),
13+
U16(Vec<u16>),
14+
U32(Vec<u32>),
15+
}
16+
17+
proptest! {
18+
#![proptest_config(ProptestConfig { cases: 64, .. ProptestConfig::default() })]
19+
#[test]
20+
fn freeze_preserves_layout(segs in prop::collection::vec(
21+
prop_oneof![
22+
prop::collection::vec(any::<u8>(), 1..4).prop_map(Segment::U8),
23+
prop::collection::vec(any::<u16>(), 1..4).prop_map(Segment::U16),
24+
prop::collection::vec(any::<u32>(), 1..4).prop_map(Segment::U32),
25+
],
26+
0..4,
27+
)) {
28+
let mut area = ByteArea::new().expect("area");
29+
let mut sections = area.sections();
30+
let mut expected: Vec<u8> = Vec::new();
31+
32+
for seg in segs {
33+
match seg {
34+
Segment::U8(data) => {
35+
let start = align_up(expected.len(), core::mem::align_of::<u8>());
36+
expected.resize(start, 0);
37+
let mut section = sections.reserve::<u8>(data.len()).expect("reserve u8");
38+
section.as_mut_slice().copy_from_slice(&data);
39+
let bytes = section.freeze().expect("freeze");
40+
expected.extend_from_slice(&data);
41+
let end = expected.len();
42+
prop_assert_eq!(bytes.as_ref(), &expected[start..end]);
43+
}
44+
Segment::U16(data) => {
45+
let start = align_up(expected.len(), core::mem::align_of::<u16>());
46+
expected.resize(start, 0);
47+
let mut section = sections.reserve::<u16>(data.len()).expect("reserve u16");
48+
section.as_mut_slice().copy_from_slice(&data);
49+
let bytes = section.freeze().expect("freeze");
50+
for v in &data {
51+
expected.extend_from_slice(&v.to_ne_bytes());
52+
}
53+
let end = expected.len();
54+
prop_assert_eq!(bytes.as_ref(), &expected[start..end]);
55+
}
56+
Segment::U32(data) => {
57+
let start = align_up(expected.len(), core::mem::align_of::<u32>());
58+
expected.resize(start, 0);
59+
let mut section = sections.reserve::<u32>(data.len()).expect("reserve u32");
60+
section.as_mut_slice().copy_from_slice(&data);
61+
let bytes = section.freeze().expect("freeze");
62+
for v in &data {
63+
expected.extend_from_slice(&v.to_ne_bytes());
64+
}
65+
let end = expected.len();
66+
prop_assert_eq!(bytes.as_ref(), &expected[start..end]);
67+
}
68+
}
69+
}
70+
71+
drop(sections);
72+
let all = area.freeze().expect("freeze area");
73+
prop_assert_eq!(all.as_ref(), expected.as_slice());
74+
}
75+
}

0 commit comments

Comments
 (0)