From afbcd0fc0b56cc6820e857017eeb86734f79aae6 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 29 Jul 2020 16:10:06 +0800 Subject: [PATCH] Replace StaticVec with SmallVec. --- Cargo.toml | 1 + doc/src/about/features.md | 2 +- src/engine.rs | 8 +- src/optimize.rs | 3 +- src/parser.rs | 24 +- src/token.rs | 48 ++-- src/utils.rs | 555 +------------------------------------- 7 files changed, 54 insertions(+), 587 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f049777e..6b2a2e55 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ categories = [ "no-std", "embedded", "wasm", "parser-implementations" ] [dependencies] num-traits = { version = "0.2.11", default-features = false } +smallvec = { version = "1.4.1", default-features = false } [features] #default = ["unchecked", "sync", "no_optimize", "no_float", "only_i32", "no_index", "no_object", "no_function", "no_module"] diff --git a/doc/src/about/features.md b/doc/src/about/features.md index ffa28cdc..245668b2 100644 --- a/doc/src/about/features.md +++ b/doc/src/about/features.md @@ -14,7 +14,7 @@ Easy * Easily [call a script-defined function]({{rootUrl}}/engine/call-fn.md) from Rust. -* Very few additional dependencies (right now only [`num-traits`](https://crates.io/crates/num-traits/) to do checked arithmetic operations); +* Very few additional dependencies (right now only [`num-traits`](https://crates.io/crates/num-traits/) to do checked arithmetic operations, and [`smallvec`](https://crates.io/crates/smallvec/)); for [`no-std`] builds, a number of additional dependencies are pulled in to provide for functionalities that used to be in `std`. Fast diff --git a/src/engine.rs b/src/engine.rs index e8cf5c3c..7806382f 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -445,7 +445,7 @@ pub fn search_imports<'s>( state: &mut State, modules: &Box, ) -> Result<&'s Module, Box> { - let (root, root_pos) = modules.get(0); + let (root, root_pos) = &modules[0]; // Qualified - check if the root module is directly indexed let index = if state.always_search { @@ -478,7 +478,7 @@ pub fn search_imports_mut<'s>( state: &mut State, modules: &Box, ) -> Result<&'s mut Module, Box> { - let (root, root_pos) = modules.get(0); + let (root, root_pos) = &modules[0]; // Qualified - check if the root module is directly indexed let index = if state.always_search { @@ -652,7 +652,7 @@ impl Engine { }; // Pop the last index value - let idx_val = idx_values.pop(); + let idx_val = idx_values.pop().unwrap(); match chain_type { #[cfg(not(feature = "no_index"))] @@ -1007,7 +1007,7 @@ impl Engine { idx_values.push(Dynamic::from(arg_values)); } Expr::FnCall(_) => unreachable!(), - Expr::Property(_) => idx_values.push(()), // Store a placeholder - no need to copy the property name + Expr::Property(_) => idx_values.push(().into()), // Store a placeholder - no need to copy the property name Expr::Index(x) | Expr::Dot(x) => { let (lhs, rhs, _) = x.as_ref(); diff --git a/src/optimize.rs b/src/optimize.rs index 27f6f816..c047cd1b 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -20,6 +20,7 @@ use crate::parser::CustomExpr; use crate::stdlib::{ boxed::Box, iter::empty, + mem, string::{String, ToString}, vec, vec::Vec, @@ -436,7 +437,7 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr { // Array literal where everything is pure - promote the indexed item. // All other items can be thrown away. state.set_dirty(); - let mut expr = a.0.take(i.0 as usize); + let mut expr = a.0.remove(i.0 as usize); expr.set_position(a.1); expr } diff --git a/src/parser.rs b/src/parser.rs index 417c35fb..03bb2a96 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1103,7 +1103,7 @@ fn parse_fn_call( eat_token(input, Token::RightParen); let hash_script = if let Some(modules) = modules.as_mut() { - modules.set_index(state.find_module(&modules.get(0).0)); + modules.set_index(state.find_module(&modules[0].0)); // Rust functions are indexed in two steps: // 1) Calculate a hash in a similar manner to script-defined functions, @@ -1145,7 +1145,7 @@ fn parse_fn_call( eat_token(input, Token::RightParen); let hash_script = if let Some(modules) = modules.as_mut() { - modules.set_index(state.find_module(&modules.get(0).0)); + modules.set_index(state.find_module(&modules[0].0)); // Rust functions are indexed in two steps: // 1) Calculate a hash in a similar manner to script-defined functions, @@ -1678,7 +1678,7 @@ fn parse_primary( // Qualifiers + variable name *hash = calc_fn_hash(modules.iter().map(|(v, _)| v.as_str()), name, 0, empty()); - modules.set_index(state.find_module(&modules.get(0).0)); + modules.set_index(state.find_module(&modules[0].0)); } _ => (), } @@ -1936,7 +1936,7 @@ fn make_dot_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result { - return Err(PERR::PropertyExpected.into_err(x.1.unwrap().get(0).1)); + return Err(PERR::PropertyExpected.into_err(x.1.unwrap()[0].1)); } // lhs.prop (lhs, prop @ Expr::Property(_)) => Expr::Dot(Box::new((lhs, prop, op_pos))), @@ -2197,25 +2197,25 @@ fn parse_binary_op( | Token::GreaterThanEqualsTo => Expr::FnCall(Box::new((op, None, hash, args, cmp_def))), Token::Or => { - let rhs = args.pop(); - let current_lhs = args.pop(); + let rhs = args.pop().unwrap(); + let current_lhs = args.pop().unwrap(); Expr::Or(Box::new((current_lhs, rhs, pos))) } Token::And => { - let rhs = args.pop(); - let current_lhs = args.pop(); + let rhs = args.pop().unwrap(); + let current_lhs = args.pop().unwrap(); Expr::And(Box::new((current_lhs, rhs, pos))) } Token::In => { - let rhs = args.pop(); - let current_lhs = args.pop(); + let rhs = args.pop().unwrap(); + let current_lhs = args.pop().unwrap(); make_in_expr(current_lhs, rhs, pos)? } #[cfg(not(feature = "no_object"))] Token::Period => { - let rhs = args.pop(); - let current_lhs = args.pop(); + let rhs = args.pop().unwrap(); + let current_lhs = args.pop().unwrap(); make_dot_expr(current_lhs, rhs, pos)? } diff --git a/src/token.rs b/src/token.rs index 77187304..7d1a07ba 100644 --- a/src/token.rs +++ b/src/token.rs @@ -21,7 +21,6 @@ use crate::stdlib::{ iter::Peekable, str::{Chars, FromStr}, string::{String, ToString}, - vec::Vec, }; type LERR = LexError; @@ -747,8 +746,8 @@ pub fn parse_string_literal( pos: &mut Position, enclosing_char: char, ) -> Result { - let mut result = Vec::new(); - let mut escape = String::with_capacity(12); + let mut result: StaticVec = Default::default(); + let mut escape: StaticVec = Default::default(); loop { let next_char = stream.get_next().ok_or((LERR::UnterminatedString, *pos))?; @@ -787,8 +786,8 @@ pub fn parse_string_literal( // \x??, \u????, \U???????? ch @ 'x' | ch @ 'u' | ch @ 'U' if !escape.is_empty() => { let mut seq = escape.clone(); - seq.push(ch); escape.clear(); + seq.push(ch); let mut out_val: u32 = 0; let len = match ch { @@ -799,23 +798,31 @@ pub fn parse_string_literal( }; for _ in 0..len { - let c = stream - .get_next() - .ok_or_else(|| (LERR::MalformedEscapeSequence(seq.to_string()), *pos))?; + let c = stream.get_next().ok_or_else(|| { + ( + LERR::MalformedEscapeSequence(seq.iter().cloned().collect()), + *pos, + ) + })?; seq.push(c); pos.advance(); out_val *= 16; - out_val += c - .to_digit(16) - .ok_or_else(|| (LERR::MalformedEscapeSequence(seq.to_string()), *pos))?; + out_val += c.to_digit(16).ok_or_else(|| { + ( + LERR::MalformedEscapeSequence(seq.iter().cloned().collect()), + *pos, + ) + })?; } - result.push( - char::from_u32(out_val) - .ok_or_else(|| (LERR::MalformedEscapeSequence(seq), *pos))?, - ); + result.push(char::from_u32(out_val).ok_or_else(|| { + ( + LERR::MalformedEscapeSequence(seq.into_iter().collect()), + *pos, + ) + })?); } // \{enclosing_char} - escaped @@ -828,7 +835,12 @@ pub fn parse_string_literal( ch if enclosing_char == ch && escape.is_empty() => break, // Unknown escape sequence - _ if !escape.is_empty() => return Err((LERR::MalformedEscapeSequence(escape), *pos)), + _ if !escape.is_empty() => { + return Err(( + LERR::MalformedEscapeSequence(escape.into_iter().collect()), + *pos, + )) + } // Cannot have new-lines inside string literals '\n' => { @@ -983,7 +995,7 @@ fn get_next_token_inner( // digit ... ('0'..='9', _) => { - let mut result = Vec::new(); + let mut result: StaticVec = Default::default(); let mut radix_base: Option = None; result.push(c); @@ -1385,7 +1397,7 @@ fn get_identifier( start_pos: Position, first_char: char, ) -> Option<(Token, Position)> { - let mut result = Vec::new(); + let mut result: StaticVec<_> = Default::default(); result.push(first_char); while let Some(next_char) = stream.peek_next() { @@ -1400,7 +1412,7 @@ fn get_identifier( let is_valid_identifier = is_valid_identifier(result.iter().cloned()); - let identifier: String = result.into_iter().collect(); + let identifier = result.into_iter().collect(); if !is_valid_identifier { return Some(( diff --git a/src/utils.rs b/src/utils.rs index 760c809e..a6cfeb26 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,8 +1,4 @@ //! Module containing various utility types and functions. -//! -//! # Safety -//! -//! The `StaticVec` type has some `unsafe` blocks to handle conversions between `MaybeUninit` and regular types. use crate::fn_native::{shared_make_mut, shared_take, Shared}; @@ -13,12 +9,9 @@ use crate::stdlib::{ fmt, hash::{BuildHasher, Hash, Hasher}, iter::FromIterator, - mem, - mem::MaybeUninit, - ops::{Add, AddAssign, Deref, DerefMut, Drop, Index, IndexMut}, + ops::{Add, AddAssign, Deref}, str::FromStr, string::{String, ToString}, - vec::Vec, }; #[cfg(not(feature = "no_std"))] @@ -27,6 +20,8 @@ use crate::stdlib::collections::hash_map::DefaultHasher; #[cfg(feature = "no_std")] use ahash::AHasher; +use smallvec::SmallVec; + /// A hasher that only takes one single `u64` and returns it as a hash key. /// /// # Panics @@ -92,549 +87,7 @@ pub fn calc_fn_spec<'a>( s.finish() } -/// [INTERNALS] An array-like type that holds a number of values in static storage for no-allocation, quick access. -/// Exported under the `internals` feature only. -/// -/// If too many items are stored, it converts into using a `Vec`. -/// -/// -/// This is essentially a knock-off of the [`staticvec`](https://crates.io/crates/staticvec) crate. -/// This simplified implementation here is to avoid pulling in another crate. -/// -/// # Implementation -/// -/// A `StaticVec` holds data in _either one_ of two storages: 1) a fixed-size array of `MAX_STATIC_VEC` -/// items, and 2) a dynamic `Vec`. At any time, either one of them (or both) must be empty, depending on the -/// total number of items. -/// -/// There is a `len` field containing the total number of items held by the `StaticVec`. -/// -/// The fixed-size array (`list`) is not initialized (i.e. initialized with `MaybeUninit::uninit()`). -/// -/// When `len <= MAX_STATIC_VEC`, all elements are stored in the fixed-size array. -/// Array slots `>= len` are `MaybeUninit::uninit()` while slots `< len` are considered actual data. -/// In this scenario, the `Vec` (`more`) is empty. -/// -/// As soon as we try to push a new item into the `StaticVec` that makes the total number exceed -/// `MAX_STATIC_VEC`, all the items in the fixed-sized array are taken out, replaced with -/// `MaybeUninit::uninit()` (via `mem::replace`) and pushed into the `Vec`. -/// Then the new item is added to the `Vec`. -/// -/// Therefore, if `len > MAX_STATIC_VEC`, then the fixed-size array (`list`) is considered -/// empty and uninitialized while all data resides in the `Vec` (`more`). -/// -/// When popping an item off of the `StaticVec`, the reverse is true. When `len = MAX_STATIC_VEC + 1`, -/// after popping the item, all the items residing in the `Vec` are moved back to the fixed-size array (`list`). -/// The `Vec` will then be empty. -/// -/// Therefore, if `len <= MAX_STATIC_VEC`, data is in the fixed-size array (`list`). -/// Otherwise, data is in the `Vec` (`more`). -/// -/// # Safety -/// -/// This type uses some unsafe code (mainly for uninitialized/unused array slots) for efficiency. -/// -/// ## WARNING -/// -/// This type is volatile and may change. -// -// TODO - remove unsafe code -pub struct StaticVec { - /// Total number of values held. - len: usize, - /// Fixed-size storage for fast, no-allocation access. - list: [MaybeUninit; MAX_STATIC_VEC], - /// Dynamic storage. For spill-overs. - more: Vec, -} - -/// Maximum slots of fixed-size storage for a `StaticVec`. -/// 4 slots should be enough for most cases. -const MAX_STATIC_VEC: usize = 4; - -impl Drop for StaticVec { - fn drop(&mut self) { - self.clear(); - } -} - -impl Hash for StaticVec { - fn hash(&self, state: &mut H) { - self.iter().for_each(|x| x.hash(state)); - } -} - -impl Default for StaticVec { - fn default() -> Self { - Self { - len: 0, - list: unsafe { mem::MaybeUninit::uninit().assume_init() }, - more: Vec::new(), - } - } -} - -impl PartialEq for StaticVec { - fn eq(&self, other: &Self) -> bool { - if self.len != other.len || self.more != other.more { - return false; - } - - if self.len > MAX_STATIC_VEC { - return true; - } - - unsafe { - mem::transmute::<_, &[T; MAX_STATIC_VEC]>(&self.list) - == mem::transmute::<_, &[T; MAX_STATIC_VEC]>(&other.list) - } - } -} - -impl Clone for StaticVec { - fn clone(&self) -> Self { - let mut value: Self = Default::default(); - value.len = self.len; - - if self.is_fixed_storage() { - for x in 0..self.len { - let item = self.list.get(x).unwrap(); - let item_value = unsafe { mem::transmute::<_, &T>(item) }; - value.list[x] = MaybeUninit::new(item_value.clone()); - } - } else { - value.more = self.more.clone(); - } - - value - } -} - -impl Eq for StaticVec {} - -impl FromIterator for StaticVec { - fn from_iter>(iter: X) -> Self { - let mut vec = StaticVec::new(); - - for x in iter { - vec.push(x); - } - - vec - } -} - -impl IntoIterator for StaticVec { - type Item = T; - type IntoIter = Box>; - - fn into_iter(self) -> Self::IntoIter { - self.into_iter() - } -} - -impl StaticVec { - /// Create a new `StaticVec`. - pub fn new() -> Self { - Default::default() - } - /// Empty the `StaticVec`. - pub fn clear(&mut self) { - if self.is_fixed_storage() { - for x in 0..self.len { - self.extract_from_list(x); - } - } else { - self.more.clear(); - } - self.len = 0; - } - /// Extract a `MaybeUninit` into a concrete initialized type. - fn extract(value: MaybeUninit) -> T { - unsafe { value.assume_init() } - } - /// Extract an item from the fixed-size array, replacing it with `MaybeUninit::uninit()`. - /// - /// # Panics - /// - /// Panics if fixed-size storage is not used, or if the `index` is out of bounds. - fn extract_from_list(&mut self, index: usize) -> T { - if !self.is_fixed_storage() { - panic!("not fixed storage in StaticVec"); - } - if index >= self.len { - panic!("index OOB in StaticVec"); - } - Self::extract(mem::replace( - self.list.get_mut(index).unwrap(), - MaybeUninit::uninit(), - )) - } - /// Set an item into the fixed-size array. - /// If `drop` is `true`, the original value is extracted then automatically dropped. - /// - /// # Panics - /// - /// Panics if fixed-size storage is not used, or if the `index` is out of bounds. - fn set_into_list(&mut self, index: usize, value: T, drop: bool) { - if !self.is_fixed_storage() { - panic!("not fixed storage in StaticVec"); - } - // Allow setting at most one slot to the right - if index > self.len { - panic!("index OOB in StaticVec"); - } - let temp = mem::replace(self.list.get_mut(index).unwrap(), MaybeUninit::new(value)); - if drop { - // Extract the original value - which will drop it automatically - Self::extract(temp); - } - } - /// Move item in the fixed-size array into the `Vec`. - /// - /// # Panics - /// - /// Panics if fixed-size storage is not used, or if the fixed-size storage is not full. - fn move_fixed_into_vec(&mut self, num: usize) { - if !self.is_fixed_storage() { - panic!("not fixed storage in StaticVec"); - } - if self.len != num { - panic!("fixed storage is not full in StaticVec"); - } - self.more.extend( - self.list - .iter_mut() - .take(num) - .map(|v| mem::replace(v, MaybeUninit::uninit())) - .map(Self::extract), - ); - } - /// Is data stored in fixed-size storage? - fn is_fixed_storage(&self) -> bool { - self.len <= MAX_STATIC_VEC - } - /// Push a new value to the end of this `StaticVec`. - pub fn push>(&mut self, value: X) { - if self.len == MAX_STATIC_VEC { - self.move_fixed_into_vec(MAX_STATIC_VEC); - self.more.push(value.into()); - } else if self.is_fixed_storage() { - self.set_into_list(self.len, value.into(), false); - } else { - self.more.push(value.into()); - } - self.len += 1; - } - /// Insert a new value to this `StaticVec` at a particular position. - /// - /// # Panics - /// - /// Panics if `index` is out of bounds. - pub fn insert>(&mut self, index: usize, value: X) { - if index > self.len { - panic!("index OOB in StaticVec"); - } - - if self.len == MAX_STATIC_VEC { - self.move_fixed_into_vec(MAX_STATIC_VEC); - self.more.insert(index, value.into()); - } else if self.is_fixed_storage() { - // Move all items one slot to the right - for x in (index..self.len).rev() { - let orig_value = self.extract_from_list(x); - self.set_into_list(x + 1, orig_value, false); - } - self.set_into_list(index, value.into(), false); - } else { - self.more.insert(index, value.into()); - } - self.len += 1; - } - /// Pop a value from the end of this `StaticVec`. - /// - /// # Panics - /// - /// Panics if the `StaticVec` is empty. - pub fn pop(&mut self) -> T { - if self.is_empty() { - panic!("nothing to pop!"); - } - - if self.is_fixed_storage() { - let value = self.extract_from_list(self.len - 1); - self.len -= 1; - value - } else { - let value = self.more.pop().unwrap(); - self.len -= 1; - - // Move back to the fixed list - if self.more.len() == MAX_STATIC_VEC { - for index in (0..MAX_STATIC_VEC).rev() { - let item = self.more.pop().unwrap(); - self.set_into_list(index, item, false); - } - } - - value - } - } - /// Remove a value from this `StaticVec` at a particular position. - /// - /// # Panics - /// - /// Panics if `index` is out of bounds. - pub fn remove(&mut self, index: usize) -> T { - if index >= self.len { - panic!("index OOB in StaticVec"); - } - - if self.is_fixed_storage() { - let value = self.extract_from_list(index); - - // Move all items one slot to the left - for x in index + 1..self.len { - let orig_value = self.extract_from_list(x); - self.set_into_list(x - 1, orig_value, false); - } - self.len -= 1; - - value - } else { - let value = self.more.remove(index); - self.len -= 1; - - // Move back to the fixed list - if self.more.len() == MAX_STATIC_VEC { - for index in (0..MAX_STATIC_VEC).rev() { - let item = self.more.pop().unwrap(); - self.set_into_list(index, item, false); - } - } - - value - } - } - /// Get the number of items in this `StaticVec`. - pub fn len(&self) -> usize { - self.len - } - /// Is this `StaticVec` empty? - pub fn is_empty(&self) -> bool { - self.len == 0 - } - /// Get a reference to the item at a particular index. - /// - /// # Panics - /// - /// Panics if `index` is out of bounds. - pub fn get(&self, index: usize) -> &T { - if index >= self.len { - panic!("index OOB in StaticVec"); - } - - let list = unsafe { mem::transmute::<_, &[T; MAX_STATIC_VEC]>(&self.list) }; - - if self.is_fixed_storage() { - list.get(index).unwrap() - } else { - self.more.get(index).unwrap() - } - } - /// Get a mutable reference to the item at a particular index. - /// - /// # Panics - /// - /// Panics if `index` is out of bounds. - pub fn get_mut(&mut self, index: usize) -> &mut T { - if index >= self.len { - panic!("index OOB in StaticVec"); - } - - let list = unsafe { mem::transmute::<_, &mut [T; MAX_STATIC_VEC]>(&mut self.list) }; - - if self.is_fixed_storage() { - list.get_mut(index).unwrap() - } else { - self.more.get_mut(index).unwrap() - } - } - /// Get an iterator to entries in the `StaticVec`. - pub fn iter(&self) -> impl Iterator { - let list = unsafe { mem::transmute::<_, &[T; MAX_STATIC_VEC]>(&self.list) }; - - if self.is_fixed_storage() { - list[..self.len].iter() - } else { - self.more.iter() - } - } - /// Get a mutable iterator to entries in the `StaticVec`. - pub fn iter_mut(&mut self) -> impl Iterator { - let list = unsafe { mem::transmute::<_, &mut [T; MAX_STATIC_VEC]>(&mut self.list) }; - - if self.is_fixed_storage() { - list[..self.len].iter_mut() - } else { - self.more.iter_mut() - } - } -} - -impl StaticVec { - /// Get a mutable iterator to entries in the `StaticVec`. - pub fn into_iter(mut self) -> Box> { - if self.is_fixed_storage() { - let mut it = FixedStorageIterator { - data: unsafe { mem::MaybeUninit::uninit().assume_init() }, - index: 0, - limit: self.len, - }; - - for x in 0..self.len { - it.data[x] = mem::replace(self.list.get_mut(x).unwrap(), MaybeUninit::uninit()); - } - self.len = 0; - - Box::new(it) - } else { - Box::new(Vec::from(self).into_iter()) - } - } -} - -/// An iterator that takes control of the fixed-size storage of a `StaticVec` and returns its values. -struct FixedStorageIterator { - data: [MaybeUninit; MAX_STATIC_VEC], - index: usize, - limit: usize, -} - -impl Iterator for FixedStorageIterator { - type Item = T; - - fn next(&mut self) -> Option { - if self.index >= self.limit { - None - } else { - self.index += 1; - - let value = mem::replace( - self.data.get_mut(self.index - 1).unwrap(), - MaybeUninit::uninit(), - ); - - unsafe { Some(value.assume_init()) } - } - } -} - -impl StaticVec { - /// Get the item at a particular index, replacing it with the default. - /// - /// # Panics - /// - /// Panics if `index` is out of bounds. - pub fn take(&mut self, index: usize) -> T { - if index >= self.len { - panic!("index OOB in StaticVec"); - } - - mem::take(if self.is_fixed_storage() { - unsafe { mem::transmute(self.list.get_mut(index).unwrap()) } - } else { - self.more.get_mut(index).unwrap() - }) - } -} - -impl fmt::Debug for StaticVec { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&self.iter().collect::>(), f) - } -} - -impl AsRef<[T]> for StaticVec { - fn as_ref(&self) -> &[T] { - let list = unsafe { mem::transmute::<_, &[T; MAX_STATIC_VEC]>(&self.list) }; - - if self.is_fixed_storage() { - &list[..self.len] - } else { - &self.more[..] - } - } -} - -impl AsMut<[T]> for StaticVec { - fn as_mut(&mut self) -> &mut [T] { - let list = unsafe { mem::transmute::<_, &mut [T; MAX_STATIC_VEC]>(&mut self.list) }; - - if self.is_fixed_storage() { - &mut list[..self.len] - } else { - &mut self.more[..] - } - } -} - -impl Deref for StaticVec { - type Target = [T]; - fn deref(&self) -> &Self::Target { - self.as_ref() - } -} - -impl DerefMut for StaticVec { - fn deref_mut(&mut self) -> &mut Self::Target { - self.as_mut() - } -} - -impl Index for StaticVec { - type Output = T; - - fn index(&self, index: usize) -> &Self::Output { - self.get(index) - } -} - -impl IndexMut for StaticVec { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - self.get_mut(index) - } -} - -impl From> for Vec { - fn from(mut value: StaticVec) -> Self { - if value.len <= MAX_STATIC_VEC { - value.move_fixed_into_vec(value.len); - } - value.len = 0; - - let mut arr = Self::new(); - arr.append(&mut value.more); - arr - } -} - -impl From> for StaticVec { - fn from(mut value: Vec) -> Self { - let mut arr: Self = Default::default(); - arr.len = value.len(); - - if arr.len <= MAX_STATIC_VEC { - for x in (0..arr.len).rev() { - arr.set_into_list(x, value.pop().unwrap(), false); - } - } else { - arr.more = value; - } - - arr - } -} +pub type StaticVec = SmallVec<[T; 4]>; /// The system immutable string type. ///