Merge branch 'master' into plugins
This commit is contained in:
commit
7ea341833c
@ -145,6 +145,8 @@ impl dyn Variant {
|
|||||||
pub struct Dynamic(pub(crate) Union);
|
pub struct Dynamic(pub(crate) Union);
|
||||||
|
|
||||||
/// Internal `Dynamic` representation.
|
/// Internal `Dynamic` representation.
|
||||||
|
///
|
||||||
|
/// Most variants are boxed to reduce the size.
|
||||||
pub enum Union {
|
pub enum Union {
|
||||||
Unit(()),
|
Unit(()),
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
@ -330,6 +332,12 @@ fn cast_box<X: Variant, T: Variant>(item: Box<X>) -> Result<Box<T>, Box<X>> {
|
|||||||
impl Dynamic {
|
impl Dynamic {
|
||||||
/// Create a `Dynamic` from any type. A `Dynamic` value is simply returned as is.
|
/// Create a `Dynamic` from any type. A `Dynamic` value is simply returned as is.
|
||||||
///
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This type uses some unsafe code, mainly for type casting.
|
||||||
|
///
|
||||||
|
/// # Notes
|
||||||
|
///
|
||||||
/// Beware that you need to pass in an `Array` type for it to be recognized as an `Array`.
|
/// Beware that you need to pass in an `Array` type for it to be recognized as an `Array`.
|
||||||
/// A `Vec<T>` does not get automatically converted to an `Array`, but will be a generic
|
/// A `Vec<T>` does not get automatically converted to an `Array`, but will be a generic
|
||||||
/// restricted trait object instead, because `Vec<T>` is not a supported standard type.
|
/// restricted trait object instead, because `Vec<T>` is not a supported standard type.
|
||||||
|
@ -10,6 +10,7 @@ use crate::parser::{parse, parse_global_expr, AST};
|
|||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use crate::token::{lex, Position};
|
use crate::token::{lex, Position};
|
||||||
|
use crate::utils::StaticVec;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
use crate::engine::Map;
|
use crate::engine::Map;
|
||||||
@ -20,7 +21,6 @@ use crate::stdlib::{
|
|||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
mem,
|
mem,
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
vec::Vec,
|
|
||||||
};
|
};
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
use crate::stdlib::{fs::File, io::prelude::*, path::PathBuf};
|
use crate::stdlib::{fs::File, io::prelude::*, path::PathBuf};
|
||||||
@ -994,7 +994,7 @@ impl Engine {
|
|||||||
args: A,
|
args: A,
|
||||||
) -> Result<T, Box<EvalAltResult>> {
|
) -> Result<T, Box<EvalAltResult>> {
|
||||||
let mut arg_values = args.into_vec();
|
let mut arg_values = args.into_vec();
|
||||||
let mut args: Vec<_> = arg_values.iter_mut().collect();
|
let mut args: StaticVec<_> = arg_values.iter_mut().collect();
|
||||||
let fn_lib = ast.fn_lib();
|
let fn_lib = ast.fn_lib();
|
||||||
let pos = Position::none();
|
let pos = Position::none();
|
||||||
|
|
||||||
@ -1004,7 +1004,7 @@ impl Engine {
|
|||||||
|
|
||||||
let state = State::new(fn_lib);
|
let state = State::new(fn_lib);
|
||||||
|
|
||||||
let result = self.call_script_fn(Some(scope), &state, fn_def, &mut args, pos, 0)?;
|
let result = self.call_script_fn(Some(scope), &state, fn_def, args.as_mut(), pos, 0)?;
|
||||||
|
|
||||||
let return_type = self.map_type_name(result.type_name());
|
let return_type = self.map_type_name(result.type_name());
|
||||||
|
|
||||||
|
@ -109,12 +109,12 @@ impl Target<'_> {
|
|||||||
.as_char()
|
.as_char()
|
||||||
.map_err(|_| EvalAltResult::ErrorCharMismatch(pos))?;
|
.map_err(|_| EvalAltResult::ErrorCharMismatch(pos))?;
|
||||||
|
|
||||||
let mut chars: Vec<char> = s.chars().collect();
|
let mut chars: StaticVec<char> = s.chars().collect();
|
||||||
let ch = chars[x.1];
|
let ch = *chars.get_ref(x.1);
|
||||||
|
|
||||||
// See if changed - if so, update the String
|
// See if changed - if so, update the String
|
||||||
if ch != new_ch {
|
if ch != new_ch {
|
||||||
chars[x.1] = new_ch;
|
*chars.get_mut(x.1) = new_ch;
|
||||||
s.clear();
|
s.clear();
|
||||||
chars.iter().for_each(|&ch| s.push(ch));
|
chars.iter().for_each(|&ch| s.push(ch));
|
||||||
}
|
}
|
||||||
@ -194,7 +194,7 @@ pub struct FunctionsLib(HashMap<u64, ScriptedFunction>);
|
|||||||
|
|
||||||
impl FunctionsLib {
|
impl FunctionsLib {
|
||||||
/// Create a new `FunctionsLib` from a collection of `FnDef`.
|
/// Create a new `FunctionsLib` from a collection of `FnDef`.
|
||||||
pub fn from_vec(vec: Vec<FnDef>) -> Self {
|
pub fn from_iter(vec: impl IntoIterator<Item = FnDef>) -> Self {
|
||||||
FunctionsLib(
|
FunctionsLib(
|
||||||
vec.into_iter()
|
vec.into_iter()
|
||||||
.map(|fn_def| {
|
.map(|fn_def| {
|
||||||
@ -446,7 +446,7 @@ fn search_scope<'a>(
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
{
|
{
|
||||||
if let Some((modules, hash)) = modules {
|
if let Some((modules, hash)) = modules {
|
||||||
let (id, root_pos) = modules.get(0);
|
let (id, root_pos) = modules.get_ref(0);
|
||||||
|
|
||||||
let module = if let Some(index) = modules.index() {
|
let module = if let Some(index) = modules.index() {
|
||||||
scope
|
scope
|
||||||
@ -666,7 +666,7 @@ impl Engine {
|
|||||||
/// Function call arguments may be _consumed_ when the function requires them to be passed by value.
|
/// Function call arguments may be _consumed_ when the function requires them to be passed by value.
|
||||||
/// All function arguments not in the first position are always passed by value and thus consumed.
|
/// All function arguments not in the first position are always passed by value and thus consumed.
|
||||||
/// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`!
|
/// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`!
|
||||||
pub(crate) fn call_script_fn(
|
pub(crate) fn call_script_fn<'a>(
|
||||||
&self,
|
&self,
|
||||||
scope: Option<&mut Scope>,
|
scope: Option<&mut Scope>,
|
||||||
state: &State,
|
state: &State,
|
||||||
@ -890,9 +890,9 @@ impl Engine {
|
|||||||
match rhs {
|
match rhs {
|
||||||
// xxx.fn_name(arg_expr_list)
|
// xxx.fn_name(arg_expr_list)
|
||||||
Expr::FnCall(x) if x.1.is_none() => {
|
Expr::FnCall(x) if x.1.is_none() => {
|
||||||
let ((name, pos), modules, hash, args, def_val) = x.as_ref();
|
let ((name, pos), _, hash, _, def_val) = x.as_ref();
|
||||||
|
|
||||||
let mut args: Vec<_> = once(obj)
|
let mut args: StaticVec<_> = once(obj)
|
||||||
.chain(
|
.chain(
|
||||||
idx_val
|
idx_val
|
||||||
.downcast_mut::<StaticVec<Dynamic>>()
|
.downcast_mut::<StaticVec<Dynamic>>()
|
||||||
@ -902,7 +902,7 @@ impl Engine {
|
|||||||
.collect();
|
.collect();
|
||||||
// A function call is assumed to have side effects, so the value is changed
|
// A function call is assumed to have side effects, so the value is changed
|
||||||
// TODO - Remove assumption of side effects by checking whether the first parameter is &mut
|
// TODO - Remove assumption of side effects by checking whether the first parameter is &mut
|
||||||
self.exec_fn_call(state, name, *hash, &mut args, def_val.as_ref(), *pos, 0)
|
self.exec_fn_call(state, name, *hash, args.as_mut(), def_val.as_ref(), *pos, 0)
|
||||||
.map(|v| (v, true))
|
.map(|v| (v, true))
|
||||||
}
|
}
|
||||||
// xxx.module::fn_name(...) - syntax error
|
// xxx.module::fn_name(...) - syntax error
|
||||||
@ -1394,9 +1394,9 @@ impl Engine {
|
|||||||
let mut arg_values = args_expr
|
let mut arg_values = args_expr
|
||||||
.iter()
|
.iter()
|
||||||
.map(|expr| self.eval_expr(scope, state, expr, level))
|
.map(|expr| self.eval_expr(scope, state, expr, level))
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<StaticVec<_>, _>>()?;
|
||||||
|
|
||||||
let mut args: Vec<_> = arg_values.iter_mut().collect();
|
let mut args: StaticVec<_> = arg_values.iter_mut().collect();
|
||||||
|
|
||||||
let hash_fn_spec =
|
let hash_fn_spec =
|
||||||
calc_fn_hash(empty(), KEYWORD_EVAL, once(TypeId::of::<String>()));
|
calc_fn_hash(empty(), KEYWORD_EVAL, once(TypeId::of::<String>()));
|
||||||
@ -1410,7 +1410,7 @@ impl Engine {
|
|||||||
|
|
||||||
// Evaluate the text string as a script
|
// Evaluate the text string as a script
|
||||||
let result =
|
let result =
|
||||||
self.eval_script_expr(scope, state, args[0], args_expr[0].position());
|
self.eval_script_expr(scope, state, args.pop(), args_expr[0].position());
|
||||||
|
|
||||||
if scope.len() != prev_len {
|
if scope.len() != prev_len {
|
||||||
// IMPORTANT! If the eval defines new variables in the current scope,
|
// IMPORTANT! If the eval defines new variables in the current scope,
|
||||||
@ -1425,7 +1425,7 @@ impl Engine {
|
|||||||
state,
|
state,
|
||||||
name,
|
name,
|
||||||
*hash_fn_def,
|
*hash_fn_def,
|
||||||
&mut args,
|
args.as_mut(),
|
||||||
def_val.as_ref(),
|
def_val.as_ref(),
|
||||||
*pos,
|
*pos,
|
||||||
level,
|
level,
|
||||||
@ -1442,11 +1442,11 @@ impl Engine {
|
|||||||
let mut arg_values = args_expr
|
let mut arg_values = args_expr
|
||||||
.iter()
|
.iter()
|
||||||
.map(|expr| self.eval_expr(scope, state, expr, level))
|
.map(|expr| self.eval_expr(scope, state, expr, level))
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<StaticVec<_>, _>>()?;
|
||||||
|
|
||||||
let mut args: Vec<_> = arg_values.iter_mut().collect();
|
let mut args: StaticVec<_> = arg_values.iter_mut().collect();
|
||||||
|
|
||||||
let (id, root_pos) = modules.get(0); // First module
|
let (id, root_pos) = modules.get_ref(0); // First module
|
||||||
|
|
||||||
let module = if let Some(index) = modules.index() {
|
let module = if let Some(index) = modules.index() {
|
||||||
scope
|
scope
|
||||||
@ -1462,7 +1462,7 @@ impl Engine {
|
|||||||
|
|
||||||
// First search in script-defined functions (can override built-in)
|
// First search in script-defined functions (can override built-in)
|
||||||
if let Some(fn_def) = module.get_qualified_scripted_fn(*hash_fn_def) {
|
if let Some(fn_def) = module.get_qualified_scripted_fn(*hash_fn_def) {
|
||||||
self.call_script_fn(None, state, fn_def, &mut args, *pos, level)
|
self.call_script_fn(None, state, fn_def, args.as_mut(), *pos, level)
|
||||||
} else {
|
} else {
|
||||||
// Then search in Rust functions
|
// Then search in Rust functions
|
||||||
|
|
||||||
@ -1476,7 +1476,7 @@ impl Engine {
|
|||||||
let hash = *hash_fn_def ^ hash_fn_args;
|
let hash = *hash_fn_def ^ hash_fn_args;
|
||||||
|
|
||||||
match module.get_qualified_fn(name, hash, *pos) {
|
match module.get_qualified_fn(name, hash, *pos) {
|
||||||
Ok(func) => func(&mut args, *pos),
|
Ok(func) => func(args.as_mut(), *pos),
|
||||||
Err(_) if def_val.is_some() => Ok(def_val.clone().unwrap()),
|
Err(_) if def_val.is_some() => Ok(def_val.clone().unwrap()),
|
||||||
Err(err) => Err(err),
|
Err(err) => Err(err),
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,14 @@
|
|||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use crate::any::{Dynamic, Variant};
|
use crate::any::{Dynamic, Variant};
|
||||||
use crate::stdlib::vec::Vec;
|
use crate::utils::StaticVec;
|
||||||
|
|
||||||
/// Trait that represents arguments to a function call.
|
/// Trait that represents arguments to a function call.
|
||||||
/// Any data type that can be converted into a `Vec<Dynamic>` can be used
|
/// Any data type that can be converted into a `Vec<Dynamic>` can be used
|
||||||
/// as arguments to a function call.
|
/// as arguments to a function call.
|
||||||
pub trait FuncArgs {
|
pub trait FuncArgs {
|
||||||
/// Convert to a `Vec<Dynamic>` of the function call arguments.
|
/// Convert to a `Vec<Dynamic>` of the function call arguments.
|
||||||
fn into_vec(self) -> Vec<Dynamic>;
|
fn into_vec(self) -> StaticVec<Dynamic>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Macro to implement `FuncArgs` for tuples of standard types (each can be
|
/// Macro to implement `FuncArgs` for tuples of standard types (each can be
|
||||||
@ -19,11 +19,11 @@ macro_rules! impl_args {
|
|||||||
($($p:ident),*) => {
|
($($p:ident),*) => {
|
||||||
impl<$($p: Variant + Clone),*> FuncArgs for ($($p,)*)
|
impl<$($p: Variant + Clone),*> FuncArgs for ($($p,)*)
|
||||||
{
|
{
|
||||||
fn into_vec(self) -> Vec<Dynamic> {
|
fn into_vec(self) -> StaticVec<Dynamic> {
|
||||||
let ($($p,)*) = self;
|
let ($($p,)*) = self;
|
||||||
|
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
let mut v = Vec::new();
|
let mut v = StaticVec::new();
|
||||||
$(v.push($p.into_dynamic());)*
|
$(v.push($p.into_dynamic());)*
|
||||||
|
|
||||||
v
|
v
|
||||||
|
@ -704,30 +704,21 @@ pub fn optimize_into_ast(
|
|||||||
const fn_lib: &[(&str, usize)] = &[];
|
const fn_lib: &[(&str, usize)] = &[];
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
let lib = FunctionsLib::from_vec(
|
let lib = FunctionsLib::from_iter(functions.iter().cloned().map(|mut fn_def| {
|
||||||
functions
|
|
||||||
.iter()
|
|
||||||
.cloned()
|
|
||||||
.map(|mut fn_def| {
|
|
||||||
if !level.is_none() {
|
if !level.is_none() {
|
||||||
let pos = fn_def.body.position();
|
let pos = fn_def.body.position();
|
||||||
|
|
||||||
// Optimize the function body
|
// Optimize the function body
|
||||||
let mut body =
|
let mut body = optimize(vec![fn_def.body], engine, &Scope::new(), &fn_lib, level);
|
||||||
optimize(vec![fn_def.body], engine, &Scope::new(), &fn_lib, level);
|
|
||||||
|
|
||||||
// {} -> Noop
|
// {} -> Noop
|
||||||
fn_def.body = match body.pop().unwrap_or_else(|| Stmt::Noop(pos)) {
|
fn_def.body = match body.pop().unwrap_or_else(|| Stmt::Noop(pos)) {
|
||||||
// { return val; } -> val
|
// { return val; } -> val
|
||||||
Stmt::ReturnWithVal(x)
|
Stmt::ReturnWithVal(x) if x.1.is_some() && (x.0).0 == ReturnType::Return => {
|
||||||
if x.1.is_some() && (x.0).0 == ReturnType::Return =>
|
|
||||||
{
|
|
||||||
Stmt::Expr(Box::new(x.1.unwrap()))
|
Stmt::Expr(Box::new(x.1.unwrap()))
|
||||||
}
|
}
|
||||||
// { return; } -> ()
|
// { return; } -> ()
|
||||||
Stmt::ReturnWithVal(x)
|
Stmt::ReturnWithVal(x) if x.1.is_none() && (x.0).0 == ReturnType::Return => {
|
||||||
if x.1.is_none() && (x.0).0 == ReturnType::Return =>
|
|
||||||
{
|
|
||||||
Stmt::Expr(Box::new(Expr::Unit((x.0).1)))
|
Stmt::Expr(Box::new(Expr::Unit((x.0).1)))
|
||||||
}
|
}
|
||||||
// All others
|
// All others
|
||||||
@ -735,9 +726,7 @@ pub fn optimize_into_ast(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
fn_def
|
fn_def
|
||||||
})
|
}));
|
||||||
.collect(),
|
|
||||||
);
|
|
||||||
|
|
||||||
#[cfg(feature = "no_function")]
|
#[cfg(feature = "no_function")]
|
||||||
let lib: FunctionsLib = Default::default();
|
let lib: FunctionsLib = Default::default();
|
||||||
|
@ -267,6 +267,9 @@ impl DerefMut for Stack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A statement.
|
/// A statement.
|
||||||
|
///
|
||||||
|
/// Each variant is at most one pointer in size (for speed),
|
||||||
|
/// with everything being allocated together in one single tuple.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Stmt {
|
pub enum Stmt {
|
||||||
/// No-op.
|
/// No-op.
|
||||||
@ -368,6 +371,9 @@ type MRef = Option<Box<ModuleRef>>;
|
|||||||
type MRef = Option<ModuleRef>;
|
type MRef = Option<ModuleRef>;
|
||||||
|
|
||||||
/// An expression.
|
/// An expression.
|
||||||
|
///
|
||||||
|
/// Each variant is at most one pointer in size (for speed),
|
||||||
|
/// with everything being allocated together in one single tuple.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
/// Integer constant.
|
/// Integer constant.
|
||||||
@ -718,7 +724,7 @@ fn parse_call_expr<'a>(
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
let hash_fn_def = {
|
let hash_fn_def = {
|
||||||
if let Some(modules) = modules.as_mut() {
|
if let Some(modules) = modules.as_mut() {
|
||||||
modules.set_index(stack.find_module(&modules.get(0).0));
|
modules.set_index(stack.find_module(&modules.get_ref(0).0));
|
||||||
|
|
||||||
// Rust functions are indexed in two steps:
|
// Rust functions are indexed in two steps:
|
||||||
// 1) Calculate a hash in a similar manner to script-defined functions,
|
// 1) Calculate a hash in a similar manner to script-defined functions,
|
||||||
@ -758,7 +764,7 @@ fn parse_call_expr<'a>(
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
let hash_fn_def = {
|
let hash_fn_def = {
|
||||||
if let Some(modules) = modules.as_mut() {
|
if let Some(modules) = modules.as_mut() {
|
||||||
modules.set_index(stack.find_module(&modules.get(0).0));
|
modules.set_index(stack.find_module(&modules.get_ref(0).0));
|
||||||
|
|
||||||
// Rust functions are indexed in two steps:
|
// Rust functions are indexed in two steps:
|
||||||
// 1) Calculate a hash in a similar manner to script-defined functions,
|
// 1) Calculate a hash in a similar manner to script-defined functions,
|
||||||
@ -1232,7 +1238,7 @@ fn parse_primary<'a>(
|
|||||||
|
|
||||||
// Qualifiers + variable name
|
// Qualifiers + variable name
|
||||||
*hash = calc_fn_hash(modules.iter().map(|(v, _)| v.as_str()), name, empty());
|
*hash = calc_fn_hash(modules.iter().map(|(v, _)| v.as_str()), name, empty());
|
||||||
modules.set_index(stack.find_module(&modules.get(0).0));
|
modules.set_index(stack.find_module(&modules.get_ref(0).0));
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@ -1440,7 +1446,7 @@ fn make_dot_expr(
|
|||||||
#[cfg(feature = "no_module")]
|
#[cfg(feature = "no_module")]
|
||||||
unreachable!();
|
unreachable!();
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
return Err(PERR::PropertyExpected.into_err(x.1.unwrap().get(0).1));
|
return Err(PERR::PropertyExpected.into_err(x.1.unwrap().get_ref(0).1));
|
||||||
}
|
}
|
||||||
// lhs.dot_lhs.dot_rhs
|
// lhs.dot_lhs.dot_rhs
|
||||||
(lhs, Expr::Dot(x)) => {
|
(lhs, Expr::Dot(x)) => {
|
||||||
|
@ -7,7 +7,7 @@ use crate::token::Position;
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
use crate::module::Module;
|
use crate::module::Module;
|
||||||
|
|
||||||
use crate::stdlib::{borrow::Cow, boxed::Box, iter, vec::Vec};
|
use crate::stdlib::{borrow::Cow, boxed::Box, iter, string::String, vec::Vec};
|
||||||
|
|
||||||
/// Type of an entry in the Scope.
|
/// Type of an entry in the Scope.
|
||||||
#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
|
#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
|
||||||
|
146
src/utils.rs
146
src/utils.rs
@ -1,9 +1,12 @@
|
|||||||
//! Module containing various utility types and functions.
|
//! Module containing various utility types and functions.
|
||||||
|
//
|
||||||
|
// TODO - remove unsafe code
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
fmt,
|
fmt,
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
|
iter::FromIterator,
|
||||||
mem,
|
mem,
|
||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
@ -23,7 +26,7 @@ pub fn EMPTY_TYPE_ID() -> TypeId {
|
|||||||
/// Module names are passed in via `&str` references from an iterator.
|
/// Module names are passed in via `&str` references from an iterator.
|
||||||
/// Parameter types are passed in via `TypeId` values from an iterator.
|
/// Parameter types are passed in via `TypeId` values from an iterator.
|
||||||
///
|
///
|
||||||
/// ### Note
|
/// # Note
|
||||||
///
|
///
|
||||||
/// The first module name is skipped. Hashing starts from the _second_ module in the chain.
|
/// The first module name is skipped. Hashing starts from the _second_ module in the chain.
|
||||||
pub fn calc_fn_spec<'a>(
|
pub fn calc_fn_spec<'a>(
|
||||||
@ -47,8 +50,12 @@ pub fn calc_fn_spec<'a>(
|
|||||||
///
|
///
|
||||||
/// This is essentially a knock-off of the [`staticvec`](https://crates.io/crates/staticvec) crate.
|
/// 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.
|
/// This simplified implementation here is to avoid pulling in another crate.
|
||||||
#[derive(Clone, Hash, Default)]
|
///
|
||||||
pub struct StaticVec<T: Default + Clone> {
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This type uses some unsafe code (mainly to zero out unused array slots) for efficiency.
|
||||||
|
#[derive(Clone, Hash)]
|
||||||
|
pub struct StaticVec<T> {
|
||||||
/// Total number of values held.
|
/// Total number of values held.
|
||||||
len: usize,
|
len: usize,
|
||||||
/// Static storage. 4 slots should be enough for most cases - i.e. four levels of indirection.
|
/// Static storage. 4 slots should be enough for most cases - i.e. four levels of indirection.
|
||||||
@ -57,14 +64,44 @@ pub struct StaticVec<T: Default + Clone> {
|
|||||||
more: Vec<T>,
|
more: Vec<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Default + Clone> StaticVec<T> {
|
impl<T> Default for StaticVec<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
len: 0,
|
||||||
|
list: unsafe { mem::MaybeUninit::zeroed().assume_init() },
|
||||||
|
more: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> FromIterator<T> for StaticVec<T> {
|
||||||
|
fn from_iter<X: IntoIterator<Item = T>>(iter: X) -> Self {
|
||||||
|
let mut vec = StaticVec::new();
|
||||||
|
|
||||||
|
for x in iter {
|
||||||
|
vec.push(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> StaticVec<T> {
|
||||||
/// Create a new `StaticVec`.
|
/// Create a new `StaticVec`.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
/// Push a new value to the end of this `StaticVec`.
|
/// Push a new value to the end of this `StaticVec`.
|
||||||
pub fn push<X: Into<T>>(&mut self, value: X) {
|
pub fn push<X: Into<T>>(&mut self, value: X) {
|
||||||
if self.len >= self.list.len() {
|
if self.len == self.list.len() {
|
||||||
|
// Move the fixed list to the Vec
|
||||||
|
for x in 0..self.list.len() {
|
||||||
|
let def_val: T = unsafe { mem::MaybeUninit::zeroed().assume_init() };
|
||||||
|
self.more
|
||||||
|
.push(mem::replace(self.list.get_mut(x).unwrap(), def_val));
|
||||||
|
}
|
||||||
|
self.more.push(value.into());
|
||||||
|
} else if self.len > self.list.len() {
|
||||||
self.more.push(value.into());
|
self.more.push(value.into());
|
||||||
} else {
|
} else {
|
||||||
self.list[self.len] = value.into();
|
self.list[self.len] = value.into();
|
||||||
@ -80,9 +117,19 @@ impl<T: Default + Clone> StaticVec<T> {
|
|||||||
let result = if self.len <= 0 {
|
let result = if self.len <= 0 {
|
||||||
panic!("nothing to pop!")
|
panic!("nothing to pop!")
|
||||||
} else if self.len <= self.list.len() {
|
} else if self.len <= self.list.len() {
|
||||||
mem::take(self.list.get_mut(self.len - 1).unwrap())
|
let def_val: T = unsafe { mem::MaybeUninit::zeroed().assume_init() };
|
||||||
|
mem::replace(self.list.get_mut(self.len - 1).unwrap(), def_val)
|
||||||
} else {
|
} else {
|
||||||
self.more.pop().unwrap()
|
let r = self.more.pop().unwrap();
|
||||||
|
|
||||||
|
// Move back to the fixed list
|
||||||
|
if self.more.len() == self.list.len() {
|
||||||
|
for x in 0..self.list.len() {
|
||||||
|
self.list[self.list.len() - 1 - x] = self.more.pop().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r
|
||||||
};
|
};
|
||||||
|
|
||||||
self.len -= 1;
|
self.len -= 1;
|
||||||
@ -93,48 +140,99 @@ impl<T: Default + Clone> StaticVec<T> {
|
|||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.len
|
self.len
|
||||||
}
|
}
|
||||||
/// Get an item at a particular index.
|
/// Get a reference to the item at a particular index.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if the index is out of bounds.
|
/// Panics if the index is out of bounds.
|
||||||
pub fn get(&self, index: usize) -> &T {
|
pub fn get_ref(&self, index: usize) -> &T {
|
||||||
if index >= self.len {
|
if index >= self.len {
|
||||||
panic!("index OOB in StaticVec");
|
panic!("index OOB in StaticVec");
|
||||||
}
|
}
|
||||||
|
|
||||||
if index < self.list.len() {
|
if self.len < self.list.len() {
|
||||||
self.list.get(index).unwrap()
|
self.list.get(index).unwrap()
|
||||||
} else {
|
} else {
|
||||||
self.more.get(index - self.list.len()).unwrap()
|
self.more.get(index).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Get a mutable reference to the item at a particular index.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the index is out of bounds.
|
||||||
|
pub fn get_mut(&mut self, index: usize) -> &mut T {
|
||||||
|
if index >= self.len {
|
||||||
|
panic!("index OOB in StaticVec");
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.len < self.list.len() {
|
||||||
|
self.list.get_mut(index).unwrap()
|
||||||
|
} else {
|
||||||
|
self.more.get_mut(index).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Get an iterator to entries in the `StaticVec`.
|
/// Get an iterator to entries in the `StaticVec`.
|
||||||
pub fn iter(&self) -> impl Iterator<Item = &T> {
|
pub fn iter(&self) -> impl Iterator<Item = &T> {
|
||||||
let num = if self.len >= self.list.len() {
|
if self.len > self.list.len() {
|
||||||
self.list.len()
|
self.more.iter()
|
||||||
} else {
|
} else {
|
||||||
self.len
|
self.list[..self.len].iter()
|
||||||
};
|
}
|
||||||
|
|
||||||
self.list[..num].iter().chain(self.more.iter())
|
|
||||||
}
|
}
|
||||||
/// Get a mutable iterator to entries in the `StaticVec`.
|
/// Get a mutable iterator to entries in the `StaticVec`.
|
||||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
|
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
|
||||||
let num = if self.len >= self.list.len() {
|
if self.len > self.list.len() {
|
||||||
self.list.len()
|
self.more.iter_mut()
|
||||||
} else {
|
} else {
|
||||||
self.len
|
self.list[..self.len].iter_mut()
|
||||||
};
|
}
|
||||||
|
|
||||||
self.list[..num].iter_mut().chain(self.more.iter_mut())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Default + Clone + fmt::Debug> fmt::Debug for StaticVec<T> {
|
impl<T: Copy> StaticVec<T> {
|
||||||
|
/// Get the item at a particular index.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the index is out of bounds.
|
||||||
|
pub fn get(&self, index: usize) -> T {
|
||||||
|
if index >= self.len {
|
||||||
|
panic!("index OOB in StaticVec");
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.len < self.list.len() {
|
||||||
|
*self.list.get(index).unwrap()
|
||||||
|
} else {
|
||||||
|
*self.more.get(index).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: fmt::Debug> fmt::Debug for StaticVec<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "[ ")?;
|
write!(f, "[ ")?;
|
||||||
self.iter().try_for_each(|v| write!(f, "{:?}, ", v))?;
|
self.iter().try_for_each(|v| write!(f, "{:?}, ", v))?;
|
||||||
write!(f, "]")
|
write!(f, "]")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> AsRef<[T]> for StaticVec<T> {
|
||||||
|
fn as_ref(&self) -> &[T] {
|
||||||
|
if self.len > self.list.len() {
|
||||||
|
&self.more[..]
|
||||||
|
} else {
|
||||||
|
&self.list[..self.len]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> AsMut<[T]> for StaticVec<T> {
|
||||||
|
fn as_mut(&mut self) -> &mut [T] {
|
||||||
|
if self.len > self.list.len() {
|
||||||
|
&mut self.more[..]
|
||||||
|
} else {
|
||||||
|
&mut self.list[..self.len]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user