1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use crate::{Buffer, BufferError};
impl Buffer {
/// Creates a new `Buffer` with custom initialization.
///
/// # Arguments
///
/// * `bytes` - The number of bytes to allocate.
/// * `init_fn` - A closure that initializes the buffer and returns the number of bytes actually used.
///
/// # Returns
///
/// `Ok(Buffer)` with at least `bytes` allocated, where `init_fn` has been applied to initialize some portion of it,
/// or `Err(BufferError)` if allocation fails.
///
/// # Errors
///
/// - `AllocationError` is returned if allocation fails.
///
/// # Panics
///
/// - Panics if the number of initialized bytes > number of allocated bytes.
pub fn alloc_with<F>(bytes: usize, init_fn: F) -> Result<Self, BufferError>
where
F: FnOnce(&mut [u8]) -> usize,
{
// Allocate the buffer with the specified number of bytes
let mut buffer = Self::alloc_uninit(bytes)?;
// Invoke the initialization function
let initialized_bytes = init_fn(buffer.as_mut());
// Ensure that the number of bytes initialized does not exceed the allocated size
debug_assert!(
initialized_bytes <= bytes,
"Initialized bytes ({initialized_bytes}) cannot exceed allocated bytes ({bytes})."
);
// Truncate uninitialized bytes
buffer.truncate(initialized_bytes);
// Return resulting `Buffer`
Ok(buffer)
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
#[test]
fn test_from_ffi_init_full_buffer() {
let buffer = Buffer::alloc_with(10, |slice| {
for (i, byte) in slice.iter_mut().enumerate() {
*byte = u8::try_from(i).unwrap();
}
slice.len()
})
.unwrap();
// Check if the buffer is fully initialized
assert_eq!(buffer.len(), 10);
assert_eq!(&buffer[..], &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
}
#[test]
fn test_from_ffi_init_partial_buffer() {
let buffer = Buffer::alloc_with(10, |slice| {
for (i, byte) in slice.iter_mut().enumerate() {
if i < 5 {
*byte = u8::try_from(i).unwrap();
}
}
5 // Only 5 bytes are initialized
})
.unwrap();
// Check if the buffer is partially initialized
assert_eq!(buffer.len(), 5);
assert_eq!(&buffer[..], &[0, 1, 2, 3, 4]);
}
#[test]
fn test_from_ffi_init_zero_bytes() {
let buffer = Buffer::alloc_with(10, |_slice| {
0 // No bytes are initialized
})
.unwrap();
// Check if the buffer is empty
assert_eq!(buffer.len(), 0);
assert_eq!(buffer.capacity(), 10); // Capacity should remain 10
}
#[test]
fn test_from_ffi_init_allocation_failure() {
// Assuming Buffer::alloc_uninit might fail if asking for a very large buffer
let result = Buffer::alloc_with(usize::MAX, |_slice| 0);
assert!(result.is_err());
}
#[test]
#[should_panic(expected = "Initialized bytes (11) cannot exceed allocated bytes (10).")]
fn test_from_ffi_init_panic_on_over_initialization() {
// This test should panic due to the debug_assert
let _ = Buffer::alloc_with(10, |slice| {
for (i, byte) in slice.iter_mut().enumerate() {
*byte = u8::try_from(i).unwrap();
}
11 // Trying to initialize more bytes than allocated
})
.unwrap();
}
}