Rename MmapVec::drain to split_off (#4673)

* Rename `MmapVec::drain` to `split_off`

As suggested on #4609

* Fix tests

* Make MmapVec::split_off work like Vec::split_off

Co-authored-by: Jamey Sharp <jsharp@fastly.com>
This commit is contained in:
Alex Crichton
2022-08-15 16:00:12 -05:00
committed by GitHub
parent e0d4934ef4
commit cc955e4e7e
2 changed files with 34 additions and 50 deletions

View File

@@ -1,7 +1,7 @@
use crate::Mmap;
use anyhow::{Context, Result};
use std::fs::File;
use std::ops::{Deref, DerefMut, Range, RangeTo};
use std::ops::{Deref, DerefMut, Range};
use std::path::Path;
use std::sync::Arc;
@@ -73,36 +73,25 @@ impl MmapVec {
self.mmap.is_readonly()
}
/// "Drains" leading bytes up to the end specified in `range` from this
/// `MmapVec`, returning a separately owned `MmapVec` which retains access
/// to the bytes.
/// Splits the collection into two at the given index.
///
/// This method is similar to the `Vec` type's `drain` method, except that
/// the return value is not an iterator but rather a new `MmapVec`. The
/// purpose of this method is the ability to split-off new `MmapVec` values
/// which are sub-slices of the original one.
///
/// Once data has been drained from an `MmapVec` it is no longer accessible
/// from the original `MmapVec`, it's only accessible from the returned
/// `MmapVec`. In other words ownership of the drain'd bytes is returned
/// through the `MmapVec` return value.
///
/// This `MmapVec` will shrink by `range.end` bytes, and it will only refer
/// to the bytes that come after the drain range.
/// Returns a separate `MmapVec` which shares the underlying mapping, but
/// only has access to elements in the range `[at, len)`. After the call,
/// the original `MmapVec` will be left with access to the elements in the
/// range `[0, at)`.
///
/// This is an `O(1)` operation which does not involve copies.
pub fn drain(&mut self, range: RangeTo<usize>) -> MmapVec {
let amt = range.end;
assert!(amt <= (self.range.end - self.range.start));
pub fn split_off(&mut self, at: usize) -> MmapVec {
assert!(at <= self.range.len());
// Create a new `MmapVec` which refers to the same underlying mmap, but
// has a disjoint range from ours. Our own range is adjusted to be
// disjoint just after `ret` is created.
let ret = MmapVec {
mmap: self.mmap.clone(),
range: self.range.start..self.range.start + amt,
range: at..self.range.end,
};
self.range.start += amt;
self.range.end = self.range.start + at;
return ret;
}
@@ -173,29 +162,24 @@ mod tests {
}
#[test]
fn drain() {
let mut mmap = MmapVec::from_slice(&[1, 2, 3, 4]).unwrap();
assert_eq!(mmap.len(), 4);
assert!(mmap.drain(..0).is_empty());
assert_eq!(mmap.len(), 4);
let one = mmap.drain(..1);
assert_eq!(one.len(), 1);
assert_eq!(one[0], 1);
assert_eq!(mmap.len(), 3);
assert_eq!(&mmap[..], &[2, 3, 4]);
drop(one);
assert_eq!(mmap.len(), 3);
let two = mmap.drain(..2);
assert_eq!(two.len(), 2);
assert_eq!(two[0], 2);
assert_eq!(two[1], 3);
assert_eq!(mmap.len(), 1);
assert_eq!(mmap[0], 4);
drop(two);
assert!(mmap.drain(..0).is_empty());
assert!(mmap.drain(..1).len() == 1);
assert!(mmap.is_empty());
assert!(mmap.drain(..0).is_empty());
fn split_off() {
let mut vec = Vec::from([1, 2, 3, 4]);
let mut mmap = MmapVec::from_slice(&vec).unwrap();
assert_eq!(&mmap[..], &vec[..]);
// remove nothing; vec length remains 4
assert_eq!(&mmap.split_off(4)[..], &vec.split_off(4)[..]);
assert_eq!(&mmap[..], &vec[..]);
// remove 1 element; vec length is now 3
assert_eq!(&mmap.split_off(3)[..], &vec.split_off(3)[..]);
assert_eq!(&mmap[..], &vec[..]);
// remove 2 elements; vec length is now 1
assert_eq!(&mmap.split_off(1)[..], &vec.split_off(1)[..]);
assert_eq!(&mmap[..], &vec[..]);
// remove last element; vec length is now 0
assert_eq!(&mmap.split_off(0)[..], &vec.split_off(0)[..]);
assert_eq!(&mmap[..], &vec[..]);
// nothing left to remove, but that's okay
assert_eq!(&mmap.split_off(0)[..], &vec.split_off(0)[..]);
assert_eq!(&mmap[..], &vec[..]);
}
}

View File

@@ -268,11 +268,11 @@ impl<'a> SerializedModule<'a> {
// First validate that this is at least somewhat an elf file within
// `mmap` and additionally skip to the end of the elf file to find our
// metadata.
let elf = take_first_elf(&mut mmap)?;
let metadata = data_after_elf(&mut mmap)?;
// The metadata has a few guards up front which we process first, and
// eventually this bottoms out in a `bincode::deserialize` call.
let metadata = mmap
let metadata = metadata
.strip_prefix(HEADER)
.ok_or_else(|| anyhow!("bytes are not a compatible serialized wasmtime module"))?;
if metadata.is_empty() {
@@ -309,13 +309,13 @@ impl<'a> SerializedModule<'a> {
.context("deserialize compilation artifacts")?;
return Ok(SerializedModule {
artifacts: MyCow::Owned(elf),
artifacts: MyCow::Owned(mmap),
metadata,
});
/// This function will return the trailing data behind the ELF file
/// parsed from `data` which is where we find our metadata section.
fn take_first_elf(mmap: &mut MmapVec) -> Result<MmapVec> {
fn data_after_elf(mmap: &mut MmapVec) -> Result<MmapVec> {
use object::NativeEndian as NE;
// There's not actually a great utility for figuring out where
// the end of an ELF file is in the `object` crate. In lieu of that
@@ -335,7 +335,7 @@ impl<'a> SerializedModule<'a> {
.section_headers(NE, data)
.context("failed to read section headers")?;
let range = subslice_range(object::bytes_of_slice(sections), data);
Ok(mmap.drain(..range.end))
Ok(mmap.split_off(range.end))
}
}