use crate::alloc::{TryClone, try_realloc};
use crate::error::OutOfMemory;
use core::borrow::Borrow;
use core::{
cmp::Ordering,
fmt, mem,
num::NonZeroUsize,
ops::{Deref, DerefMut, Index, IndexMut},
slice::SliceIndex,
};
#[cfg(feature = "serde")]
use serde::ser::SerializeSeq;
use std_alloc::alloc::Layout;
use std_alloc::boxed::Box;
use std_alloc::vec::Vec as StdVec;
#[macro_export]
macro_rules! try_vec {
( $( $elem:expr ),* ) => {{
let len = $crate::private_len!( $( $elem ),* );
$crate::alloc::TryVec::with_capacity(len).and_then(|mut v| {
$( v.push($elem)?; )*
let _ = &mut v;
Ok(v)
})
}};
( $elem:expr; $len:expr ) => {{
let len: usize = $len;
if let Some(len) = ::core::num::NonZeroUsize::new(len) {
let elem = $elem;
$crate::alloc::TryVec::from_elem(elem, len)
} else {
Ok($crate::alloc::TryVec::new())
}
}};
}
#[doc(hidden)]
#[macro_export]
macro_rules! private_len {
( ) => { 0 };
( $e:expr $( , $es:expr )* ) => { 1 + $crate::private_len!( $( $es ),* ) };
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TryVec<T> {
inner: StdVec<T>,
}
impl<T> Default for TryVec<T> {
fn default() -> Self {
Self {
inner: Default::default(),
}
}
}
impl<T: fmt::Debug> fmt::Debug for TryVec<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.inner, f)
}
}
impl<T> TryClone for TryVec<T>
where
T: TryClone,
{
fn try_clone(&self) -> Result<Self, OutOfMemory> {
let mut v = TryVec::with_capacity(self.len())?;
for x in self {
v.push(x.try_clone()?).expect("reserved capacity");
}
Ok(v)
}
}
impl<T> TryVec<T> {
pub const fn new() -> Self {
Self {
inner: StdVec::new(),
}
}
pub fn with_capacity(capacity: usize) -> Result<Self, OutOfMemory> {
let mut v = Self::new();
v.reserve(capacity)?;
Ok(v)
}
#[doc(hidden)]
#[inline]
pub fn from_elem(elem: T, len: NonZeroUsize) -> Result<Self, OutOfMemory>
where
T: TryClone,
{
let mut v = Self::with_capacity(len.get())?;
for _ in 0..len.get() - 1 {
v.push(elem.try_clone()?)?;
}
v.push(elem)?;
Ok(v)
}
pub fn reserve(&mut self, additional: usize) -> Result<(), OutOfMemory> {
self.inner.try_reserve(additional).map_err(|_| {
OutOfMemory::new(
self.len()
.saturating_add(additional)
.saturating_mul(mem::size_of::<T>()),
)
})
}
pub fn reserve_exact(&mut self, additional: usize) -> Result<(), OutOfMemory> {
self.inner
.try_reserve_exact(additional)
.map_err(|_| OutOfMemory::new(self.len().saturating_add(additional)))
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn capacity(&self) -> usize {
self.inner.capacity()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn push(&mut self, value: T) -> Result<(), OutOfMemory> {
self.reserve(1)?;
self.inner.push(value);
Ok(())
}
pub fn pop(&mut self) -> Option<T> {
self.inner.pop()
}
pub fn truncate(&mut self, len: usize) {
self.inner.truncate(len);
}
pub fn resize(&mut self, new_len: usize, value: T) -> Result<(), OutOfMemory>
where
T: TryClone,
{
match new_len.cmp(&self.len()) {
Ordering::Less => self.truncate(new_len),
Ordering::Equal => {}
Ordering::Greater => {
let delta = new_len - self.len();
self.reserve(delta)?;
for _ in 0..delta - 1 {
self.push(value.try_clone()?)?;
}
self.push(value)?;
}
}
Ok(())
}
pub fn resize_with<F>(&mut self, new_len: usize, f: F) -> Result<(), OutOfMemory>
where
F: FnMut() -> T,
{
let len = self.len();
if new_len > len {
self.reserve(new_len - len)?;
}
self.inner.resize_with(new_len, f);
Ok(())
}
pub fn retain<F>(&mut self, f: F)
where
F: FnMut(&T) -> bool,
{
self.inner.retain(f);
}
pub fn retain_mut<F>(&mut self, f: F)
where
F: FnMut(&mut T) -> bool,
{
self.inner.retain_mut(f);
}
pub fn into_raw_parts(mut self) -> (*mut T, usize, usize) {
#[cfg(not(miri))]
{
let ptr = self.as_mut_ptr();
let len = self.len();
let cap = self.capacity();
mem::forget(self);
(ptr, len, cap)
}
#[cfg(miri)]
{
let _ = &mut self;
self.inner.into_raw_parts()
}
}
pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Self {
TryVec {
inner: unsafe { StdVec::from_raw_parts(ptr, length, capacity) },
}
}
pub fn drain<R>(&mut self, range: R) -> std_alloc::vec::Drain<'_, T>
where
R: core::ops::RangeBounds<usize>,
{
self.inner.drain(range)
}
pub fn shrink_to_fit(&mut self) -> Result<(), OutOfMemory> {
if self.len() == self.capacity() {
return Ok(());
}
if self.is_empty() || mem::size_of::<T>() == 0 {
self.inner.shrink_to_fit();
return Ok(());
}
let (ptr, len, cap) = mem::take(self).into_raw_parts();
let layout = Layout::array::<T>(cap).unwrap();
let new_size = Layout::array::<T>(len).unwrap().size();
let result = unsafe { try_realloc(ptr.cast(), layout, new_size) };
match result {
Ok(ptr) => {
*self = unsafe { Self::from_raw_parts(ptr.cast::<T>().as_ptr(), len, len) };
Ok(())
}
Err(oom) => {
*self = unsafe { TryVec::from_raw_parts(ptr, len, cap) };
Err(oom)
}
}
}
pub fn into_boxed_slice(mut self) -> Result<Box<[T]>, OutOfMemory> {
self.shrink_to_fit()?;
Ok(self.inner.into_boxed_slice())
}
pub fn clear(&mut self) {
self.inner.clear();
}
pub fn as_mut_ptr(&mut self) -> *mut T {
self.inner.as_mut_ptr()
}
}
impl<T> Deref for TryVec<T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<T> DerefMut for TryVec<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl<T> AsRef<[T]> for TryVec<T> {
fn as_ref(&self) -> &[T] {
self
}
}
impl<T> Borrow<[T]> for TryVec<T> {
fn borrow(&self) -> &[T] {
self
}
}
impl<T, I> Index<I> for TryVec<T>
where
I: SliceIndex<[T]>,
{
type Output = <I as SliceIndex<[T]>>::Output;
fn index(&self, index: I) -> &Self::Output {
&self.inner[index]
}
}
impl<T, I> IndexMut<I> for TryVec<T>
where
I: SliceIndex<[T]>,
{
fn index_mut(&mut self, index: I) -> &mut Self::Output {
&mut self.inner[index]
}
}
impl<T> IntoIterator for TryVec<T> {
type Item = T;
type IntoIter = std_alloc::vec::IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
self.inner.into_iter()
}
}
impl<'a, T> IntoIterator for &'a TryVec<T> {
type Item = &'a T;
type IntoIter = core::slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
(**self).iter()
}
}
impl<'a, T> IntoIterator for &'a mut TryVec<T> {
type Item = &'a mut T;
type IntoIter = core::slice::IterMut<'a, T>;
fn into_iter(self) -> Self::IntoIter {
(**self).iter_mut()
}
}
impl<T> From<TryVec<T>> for StdVec<T> {
fn from(v: TryVec<T>) -> Self {
v.inner
}
}
impl<T> From<StdVec<T>> for TryVec<T> {
fn from(inner: StdVec<T>) -> Self {
Self { inner }
}
}
impl<T> From<Box<[T]>> for TryVec<T> {
fn from(boxed_slice: Box<[T]>) -> Self {
Self::from(StdVec::from(boxed_slice))
}
}
#[cfg(feature = "serde")]
impl<T> serde::ser::Serialize for TryVec<T>
where
T: serde::ser::Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut seq = serializer.serialize_seq(Some(self.len()))?;
for elem in self {
seq.serialize_element(elem)?;
}
seq.end()
}
}
#[cfg(feature = "serde")]
impl<'de, T> serde::de::Deserialize<'de> for TryVec<T>
where
T: serde::de::Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use core::marker::PhantomData;
struct Visitor<T>(PhantomData<fn() -> TryVec<T>>);
impl<'de, T> serde::de::Visitor<'de> for Visitor<T>
where
T: serde::de::Deserialize<'de>,
{
type Value = TryVec<T>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a `wasmtime_core::alloc::Vec` sequence")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
use serde::de::Error as _;
let mut v = TryVec::new();
if let Some(len) = seq.size_hint() {
v.reserve_exact(len).map_err(|oom| A::Error::custom(oom))?;
}
while let Some(elem) = seq.next_element()? {
v.push(elem).map_err(|oom| A::Error::custom(oom))?;
}
Ok(v)
}
}
deserializer.deserialize_seq(Visitor(PhantomData))
}
}
#[cfg(test)]
mod tests {
use super::TryVec;
use crate::error::OutOfMemory;
#[test]
fn test_into_boxed_slice() -> Result<(), OutOfMemory> {
assert_eq!(*TryVec::<i32>::new().into_boxed_slice()?, []);
let mut vec = TryVec::new();
vec.push(1)?;
assert_eq!(*vec.into_boxed_slice()?, [1]);
let mut vec = TryVec::with_capacity(2)?;
vec.push(1)?;
assert_eq!(*vec.into_boxed_slice()?, [1]);
let mut vec = TryVec::with_capacity(2)?;
vec.push(1_u128)?;
assert_eq!(*vec.into_boxed_slice()?, [1]);
assert_eq!(*TryVec::<()>::new().into_boxed_slice()?, []);
let mut vec = TryVec::new();
vec.push(())?;
assert_eq!(*vec.into_boxed_slice()?, [()]);
let vec = TryVec::<i32>::with_capacity(2)?;
assert_eq!(*vec.into_boxed_slice()?, []);
Ok(())
}
}