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

View File

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