Skip to content

Commit 4478a56

Browse files
roypatErik Schilling
andcommitted
Implement WriteVolatile for Vec<u8>
This implementation is sometimes useful for test code, to avoid having to right-size Vecs ahead of time, and then using the WriteVolatile implementation for &mut [u8]. Signed-off-by: Patrick Roy <roypat@amazon.co.uk> Co-Authored-By: Erik Schilling <erik.schilling@linaro.org>
1 parent 35397a1 commit 4478a56

File tree

2 files changed

+48
-0
lines changed

2 files changed

+48
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
- [[#256](https://github.com/rust-vmm/vm-memory/pull/256)] Implement `WriteVolatile`
88
for `std::io::Stdout`.
9+
- [[#256](https://github.com/rust-vmm/vm-memory/pull/256)] Implement `WriteVolatile`
10+
for `std::vec::Vec`.
911
- [[#256](https://github.com/rust-vmm/vm-memory/pull/256)] Implement `WriteVolatile`
1012
for `Cursor<&mut [u8]>`.
1113
- [[#256](https://github.com/rust-vmm/vm-memory/pull/256)] Implement `ReadVolatile`

src/io.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,37 @@ impl ReadVolatile for &[u8] {
280280
}
281281
}
282282

283+
// WriteVolatile implementation for Vec<u8> is based upon the Write impl for Vec, which
284+
// defers to Vec::append_elements, after which the below functionality is modelled.
285+
impl WriteVolatile for Vec<u8> {
286+
fn write_volatile<B: BitmapSlice>(
287+
&mut self,
288+
buf: &VolatileSlice<B>,
289+
) -> Result<usize, VolatileMemoryError> {
290+
let count = buf.len();
291+
self.reserve(count);
292+
let len = self.len();
293+
294+
// SAFETY: Calling Vec::reserve() above guarantees the the backing storage of the Vec has
295+
// length at least `len + count`. This means that self.as_mut_ptr().add(len) remains within
296+
// the same allocated object, the offset does not exceed isize (as otherwise reserve would
297+
// have panicked), and does not rely on address space wrapping around.
298+
// In particular, the entire `count` bytes after `self.as_mut_ptr().add(count)` is
299+
// contiguously allocated and valid for writes.
300+
// Lastly, `copy_to_volatile_slice` correctly initialized `copied_len` additional bytes
301+
// in the Vec's backing storage, and we assert this to be equal to `count`. Additionally,
302+
// `len + count` is at most the reserved capacity of the vector. Thus the call to `set_len`
303+
// is safe.
304+
unsafe {
305+
let copied_len = copy_from_volatile_slice(self.as_mut_ptr().add(len), buf, count);
306+
307+
assert_eq!(copied_len, count);
308+
self.set_len(len + count);
309+
}
310+
Ok(count)
311+
}
312+
}
313+
283314
// ReadVolatile and WriteVolatile implementations for Cursor<T> is modelled after the standard
284315
// library's implementation (modulo having to inline `Cursor::remaining_slice`, as that's nightly only)
285316
impl<T> ReadVolatile for Cursor<T>
@@ -561,4 +592,19 @@ mod tests {
561592
);
562593
assert_eq!(cursor.get_ref(), &[1, 2, 3, 4, 1, 2, 3]);
563594
}
595+
596+
#[test]
597+
fn test_write_volatile_for_vec() {
598+
let mut write_buffer = Vec::new();
599+
let mut input = [1, 2, 3, 4];
600+
601+
assert_eq!(
602+
write_buffer
603+
.write_volatile(&VolatileSlice::from(input.as_mut_slice()))
604+
.unwrap(),
605+
4
606+
);
607+
608+
assert_eq!(&write_buffer, &input);
609+
}
564610
}

0 commit comments

Comments
 (0)