Merge branch 'master' into plugins

This commit is contained in:
Stephen Chung
2020-07-25 16:16:09 +08:00
21 changed files with 404 additions and 97 deletions

View File

@@ -30,12 +30,24 @@ use crate::stdlib::time::Instant;
#[cfg(target_arch = "wasm32")]
use instant::Instant;
mod private {
use crate::fn_native::SendSync;
use crate::stdlib::any::Any;
/// A sealed trait that prevents other crates from implementing [`Variant`].
///
/// [`Variant`]: super::Variant
pub trait Sealed {}
impl<T: Any + Clone + SendSync> Sealed for T {}
}
/// Trait to represent any type.
///
/// Currently, `Variant` is not `Send` nor `Sync`, so it can practically be any type.
/// Turn on the `sync` feature to restrict it to only types that implement `Send + Sync`.
#[cfg(not(feature = "sync"))]
pub trait Variant: Any {
pub trait Variant: Any + private::Sealed {
/// Convert this `Variant` trait object to `&dyn Any`.
fn as_any(&self) -> &dyn Any;
@@ -53,10 +65,6 @@ pub trait Variant: Any {
/// Clone into `Dynamic`.
fn clone_into_dynamic(&self) -> Dynamic;
/// This trait may only be implemented by `rhai`.
#[doc(hidden)]
fn _closed(&self) -> _Private;
}
/// Trait to represent any type.
@@ -64,7 +72,7 @@ pub trait Variant: Any {
/// `From<_>` is implemented for `i64` (`i32` if `only_i32`), `f64` (if not `no_float`),
/// `bool`, `String`, `char`, `Vec<T>` (into `Array`) and `HashMap<String, T>` (into `Map`).
#[cfg(feature = "sync")]
pub trait Variant: Any + Send + Sync {
pub trait Variant: Any + Send + Sync + private::Sealed {
/// Convert this `Variant` trait object to `&dyn Any`.
fn as_any(&self) -> &dyn Any;
@@ -82,10 +90,6 @@ pub trait Variant: Any + Send + Sync {
/// Clone into `Dynamic`.
fn clone_into_dynamic(&self) -> Dynamic;
/// This trait may only be implemented by `rhai`.
#[doc(hidden)]
fn _closed(&self) -> _Private;
}
impl<T: Any + Clone + SendSync> Variant for T {
@@ -107,9 +111,6 @@ impl<T: Any + Clone + SendSync> Variant for T {
fn clone_into_dynamic(&self) -> Dynamic {
Dynamic::from(self.clone())
}
fn _closed(&self) -> _Private {
_Private
}
}
impl dyn Variant {
@@ -809,8 +810,3 @@ impl From<Box<FnPtr>> for Dynamic {
Self(Union::FnPtr(value))
}
}
/// Private type which ensures that `rhai::Any` and `rhai::AnyExt` can only
/// be implemented by this crate.
#[doc(hidden)]
pub struct _Private;

View File

@@ -11,7 +11,7 @@ use crate::parser::{Expr, FnAccess, ImmutableString, ReturnType, ScriptFnDef, St
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
use crate::result::EvalAltResult;
use crate::scope::{EntryType as ScopeEntryType, Scope};
use crate::syntax::{CustomSyntax, EvalContext, Expression};
use crate::syntax::{CustomSyntax, EvalContext};
use crate::token::Position;
use crate::utils::StaticVec;
@@ -38,7 +38,12 @@ pub type Array = Vec<Dynamic>;
#[cfg(not(feature = "no_object"))]
pub type Map = HashMap<ImmutableString, Dynamic>;
/// A stack of imported modules.
/// [INTERNALS] A stack of imported modules.
/// Exported under the `internals` feature only.
///
/// ## WARNING
///
/// This type is volatile and may change.
pub type Imports<'a> = Vec<(Cow<'a, str>, Module)>;
#[cfg(not(feature = "unchecked"))]
@@ -189,12 +194,17 @@ impl<T: Into<Dynamic>> From<T> for Target<'_> {
}
}
/// A type that holds all the current states of the Engine.
/// [INTERNALS] A type that holds all the current states of the Engine.
/// Exported under the `internals` feature only.
///
/// # Safety
///
/// This type uses some unsafe code, mainly for avoiding cloning of local variable names via
/// direct lifetime casting.
///
/// ## WARNING
///
/// This type is volatile and may change.
#[derive(Debug, Clone, Eq, PartialEq, Hash, Default)]
pub struct State {
/// Normally, access to variables are parsed with a relative offset into the scope to avoid a lookup.
@@ -1020,7 +1030,7 @@ impl Engine {
map.entry(index).or_insert(Default::default()).into()
} else {
let index = idx
.downcast_ref::<String>()
.downcast_ref::<ImmutableString>()
.ok_or_else(|| EvalAltResult::ErrorStringIndexExpr(idx_pos))?;
map.get_mut(index.as_str())
@@ -1050,19 +1060,20 @@ impl Engine {
}
}
#[cfg(not(feature = "no_object"))]
#[cfg(not(feature = "no_index"))]
_ => {
let type_name = self.map_type_name(val.type_name());
let type_name = val.type_name();
let args = &mut [val, &mut idx];
self.exec_fn_call(
state, lib, FN_IDX_GET, true, 0, args, is_ref, true, None, level,
)
.map(|(v, _)| v.into())
.map_err(|_| {
Box::new(EvalAltResult::ErrorIndexingType(
type_name.into(),
Position::none(),
))
.map_err(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(_, _) => Box::new(
EvalAltResult::ErrorIndexingType(type_name.into(), Position::none()),
),
_ => err,
})
}

View File

@@ -10,7 +10,12 @@ use crate::stdlib::{
string::{String, ToString},
};
/// Error when tokenizing the script text.
/// [INTERNALS] Error encountered when tokenizing the script text.
/// Exported under the `internals` feature only.
///
/// ## WARNING
///
/// This type is volatile and may change.
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
#[non_exhaustive]
pub enum LexError {

View File

@@ -10,7 +10,9 @@ use crate::token::{is_valid_identifier, Position};
use crate::utils::{ImmutableString, StaticVec};
use crate::Scope;
use crate::stdlib::{boxed::Box, convert::TryFrom, fmt, mem, rc::Rc, string::String, sync::Arc};
use crate::stdlib::{
boxed::Box, convert::TryFrom, fmt, mem, rc::Rc, string::String, sync::Arc, vec::Vec,
};
/// Trait that maps to `Send + Sync` only under the `sync` feature.
#[cfg(feature = "sync")]

View File

@@ -170,7 +170,7 @@ pub use token::{get_next_token, parse_string_literal, InputStream, Token, Tokeni
#[cfg(feature = "internals")]
#[deprecated(note = "this type is volatile and may change")]
pub use parser::{CustomExpr, Expr, ReturnType, ScriptFnDef, Stmt};
pub use parser::{CustomExpr, Expr, FloatWrapper, ReturnType, ScriptFnDef, Stmt};
#[cfg(feature = "internals")]
#[deprecated(note = "this type is volatile and may change")]

View File

@@ -738,18 +738,18 @@ impl Module {
/// });
/// assert!(module.contains_fn(hash));
/// ```
pub fn set_indexer_set_fn<A: Variant + Clone, B: Variant + Clone>(
pub fn set_indexer_set_fn<A: Variant + Clone, B: Variant + Clone, C: Variant + Clone>(
&mut self,
func: impl Fn(&mut A, B, A) -> FuncReturn<()> + SendSync + 'static,
func: impl Fn(&mut A, B, C) -> FuncReturn<()> + SendSync + 'static,
) -> u64 {
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
let b = mem::take(args[1]).cast::<B>();
let c = mem::take(args[2]).cast::<A>();
let c = mem::take(args[2]).cast::<C>();
let a = args[0].downcast_mut::<A>().unwrap();
func(a, b, c).map(Dynamic::from)
};
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<A>()];
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
self.set_fn(
FN_IDX_SET,
Public,
@@ -758,6 +758,40 @@ impl Module {
)
}
/// Set a pair of Rust index getter and setter functions, returning both hash keys.
/// This is a shorthand for `set_indexer_get_fn` and `set_indexer_set_fn`.
///
/// If there are similar existing Rust functions, they are replaced.
///
/// # Examples
///
/// ```
/// use rhai::{Module, ImmutableString};
///
/// let mut module = Module::new();
/// let (hash_get, hash_set) = module.set_indexer_get_set_fn(
/// |x: &mut i64, y: ImmutableString| {
/// Ok(*x + y.len() as i64)
/// },
/// |x: &mut i64, y: ImmutableString, value: i64| {
/// *x = y.len() as i64 + value;
/// Ok(())
/// }
/// );
/// assert!(module.contains_fn(hash_get));
/// assert!(module.contains_fn(hash_set));
/// ```
pub fn set_indexer_get_set_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
&mut self,
getter: impl Fn(&mut A, B) -> FuncReturn<T> + SendSync + 'static,
setter: impl Fn(&mut A, B, T) -> FuncReturn<()> + SendSync + 'static,
) -> (u64, u64) {
(
self.set_indexer_get_fn(getter),
self.set_indexer_set_fn(setter),
)
}
/// Set a Rust function taking four parameters into the module, returning a hash key.
///
/// If there is a similar existing Rust function, it is replaced.
@@ -1094,11 +1128,17 @@ impl Module {
}
}
/// A chain of module names to qualify a variable or function call.
/// A `u64` hash key is kept for quick search purposes.
/// [INTERNALS] A chain of module names to qualify a variable or function call.
/// Exported under the `internals` feature only.
///
/// A `u64` hash key is cached for quick search purposes.
///
/// A `StaticVec` is used because most module-level access contains only one level,
/// and it is wasteful to always allocate a `Vec` with one element.
///
/// ## WARNING
///
/// This type is volatile and may change.
#[derive(Clone, Eq, PartialEq, Default, Hash)]
pub struct ModuleRef(StaticVec<(String, Position)>, Option<NonZeroUsize>);

View File

@@ -456,7 +456,7 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
// "xxx" in "xxxxx"
(Expr::StringConstant(a), Expr::StringConstant(b)) => {
state.set_dirty();
if b.0.contains(a.0.as_ref()) { Expr::True(a.1) } else { Expr::False(a.1) }
if b.0.contains(a.0.as_str()) { Expr::True(a.1) } else { Expr::False(a.1) }
}
// 'x' in "xxxxx"
(Expr::CharConstant(a), Expr::StringConstant(b)) => {
@@ -560,7 +560,7 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
let has_script_fn = state.lib.iter_fn().find(|(_, _, _, f)| {
if !f.is_script() { return false; }
let fn_def = f.get_fn_def();
&fn_def.name == name && (args.len()..=args.len() + 1).contains(&fn_def.params.len())
fn_def.name.as_str() == name && (args.len()..=args.len() + 1).contains(&fn_def.params.len())
}).is_some();
#[cfg(feature = "no_function")]

View File

@@ -342,11 +342,16 @@ impl fmt::Display for FnAccess {
}
}
/// A scripted function definition.
/// [INTERNALS] A type containing information on a scripted function.
/// Exported under the `internals` feature only.
///
/// ## WARNING
///
/// This type is volatile and may change.
#[derive(Debug, Clone, Hash)]
pub struct ScriptFnDef {
/// Function name.
pub name: String,
pub name: ImmutableString,
/// Function access mode.
pub access: FnAccess,
/// Names of function parameters.
@@ -376,7 +381,12 @@ impl fmt::Display for ScriptFnDef {
}
}
/// `return`/`throw` statement.
/// [INTERNALS] A type encapsulating the mode of a `return`/`throw` statement.
/// Exported under the `internals` feature only.
///
/// ## WARNING
///
/// This type is volatile and may change.
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
pub enum ReturnType {
/// `return` statement.
@@ -477,7 +487,8 @@ impl ParseSettings {
}
}
/// A statement.
/// [INTERNALS] A Rhai statement.
/// Exported under the `internals` feature only.
///
/// Each variant is at most one pointer in size (for speed),
/// with everything being allocated together in one single tuple.
@@ -582,6 +593,12 @@ impl Stmt {
}
}
/// [INTERNALS] A type wrapping a custom syntax definition.
/// Exported under the `internals` feature only.
///
/// ## WARNING
///
/// This type is volatile and may change.
#[derive(Clone)]
pub struct CustomExpr(pub StaticVec<Expr>, pub Shared<FnCustomSyntaxEval>);
@@ -592,11 +609,20 @@ impl fmt::Debug for CustomExpr {
}
impl Hash for CustomExpr {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
/// [INTERNALS] A type wrapping a floating-point number.
/// Exported under the `internals` feature only.
///
/// This type is mainly used to provide a standard `Hash` implementation
/// to floating-point numbers, allowing `Expr` to derive `Hash` automatically.
///
/// ## WARNING
///
/// This type is volatile and may change.
#[cfg(not(feature = "no_float"))]
#[derive(Debug, PartialEq, PartialOrd, Clone)]
pub struct FloatWrapper(pub FLOAT, pub Position);
@@ -609,10 +635,15 @@ impl Hash for FloatWrapper {
}
}
/// An expression.
/// [INTERNALS] An expression sub-tree.
/// Exported under the `internals` feature only.
///
/// Each variant is at most one pointer in size (for speed),
/// with everything being allocated together in one single tuple.
///
/// ## WARNING
///
/// This type is volatile and may change.
#[derive(Debug, Clone, Hash)]
pub enum Expr {
/// Integer constant.
@@ -2852,7 +2883,7 @@ fn parse_fn(
let params = params.into_iter().map(|(p, _)| p).collect();
Ok(ScriptFnDef {
name,
name: name.into(),
access,
params,
body,
@@ -2940,7 +2971,7 @@ fn parse_anon_fn(
let hash = s.finish();
// Create unique function name
let fn_name = format!("{}{}", FN_ANONYMOUS, hash);
let fn_name: ImmutableString = format!("{}{:16x}", FN_ANONYMOUS, hash).into();
let script = ScriptFnDef {
name: fn_name.clone(),
@@ -2950,7 +2981,7 @@ fn parse_anon_fn(
pos: settings.pos,
};
let expr = Expr::FnPointer(Box::new((fn_name.into(), settings.pos)));
let expr = Expr::FnPointer(Box::new((fn_name, settings.pos)));
Ok((expr, script))
}

View File

@@ -162,10 +162,12 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
Union::Variant(value) if value.is::<i16>() => self.deserialize_i16(visitor),
Union::Variant(value) if value.is::<i32>() => self.deserialize_i32(visitor),
Union::Variant(value) if value.is::<i64>() => self.deserialize_i64(visitor),
Union::Variant(value) if value.is::<i128>() => self.deserialize_i128(visitor),
Union::Variant(value) if value.is::<u8>() => self.deserialize_u8(visitor),
Union::Variant(value) if value.is::<u16>() => self.deserialize_u16(visitor),
Union::Variant(value) if value.is::<u32>() => self.deserialize_u32(visitor),
Union::Variant(value) if value.is::<u64>() => self.deserialize_u64(visitor),
Union::Variant(value) if value.is::<u128>() => self.deserialize_u128(visitor),
Union::Variant(_) => self.type_error(),
}
@@ -219,6 +221,18 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
}
}
fn deserialize_i128<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
if let Ok(v) = self.value.as_int() {
self.deserialize_int(v, visitor)
} else if cfg!(not(feature = "only_i32")) {
self.type_error()
} else {
self.value
.downcast_ref::<i128>()
.map_or_else(|| self.type_error(), |&x| visitor.visit_i128(x))
}
}
fn deserialize_u8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
if let Ok(v) = self.value.as_int() {
self.deserialize_int(v, visitor)
@@ -259,6 +273,16 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
}
}
fn deserialize_u128<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
if let Ok(v) = self.value.as_int() {
self.deserialize_int(v, visitor)
} else {
self.value
.downcast_ref::<u128>()
.map_or_else(|| self.type_error(), |&x| visitor.visit_u128(x))
}
}
fn deserialize_f32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
#[cfg(not(feature = "no_float"))]
return self

View File

@@ -150,6 +150,21 @@ impl Serializer for &mut DynamicSerializer {
}
}
fn serialize_i128(self, v: i128) -> Result<Self::Ok, Box<EvalAltResult>> {
#[cfg(not(feature = "only_i32"))]
if v > i64::MAX as i128 {
return Ok(Dynamic::from(v));
} else {
return self.serialize_i64(v as i64);
}
#[cfg(feature = "only_i32")]
if v > i32::MAX as i128 {
return Ok(Dynamic::from(v));
} else {
return self.serialize_i32(v as i32);
}
}
fn serialize_u8(self, v: u8) -> Result<Self::Ok, Box<EvalAltResult>> {
#[cfg(not(feature = "only_i32"))]
return self.serialize_i64(i64::from(v));
@@ -190,6 +205,21 @@ impl Serializer for &mut DynamicSerializer {
}
}
fn serialize_u128(self, v: u128) -> Result<Self::Ok, Box<EvalAltResult>> {
#[cfg(not(feature = "only_i32"))]
if v > i64::MAX as u128 {
return Ok(Dynamic::from(v));
} else {
return self.serialize_i64(v as i64);
}
#[cfg(feature = "only_i32")]
if v > i32::MAX as u128 {
return Ok(Dynamic::from(v));
} else {
return self.serialize_i32(v as i32);
}
}
fn serialize_f32(self, v: f32) -> Result<Self::Ok, Box<EvalAltResult>> {
Ok(Dynamic::from(v))
}

View File

@@ -12,7 +12,8 @@ use crate::token::{is_valid_identifier, Position, Token};
use crate::utils::StaticVec;
use crate::stdlib::{
fmt,
boxed::Box,
fmt, format,
rc::Rc,
string::{String, ToString},
sync::Arc,

View File

@@ -136,89 +136,181 @@ impl fmt::Debug for Position {
}
}
/// Tokens.
/// [INTERNALS] A Rhai language token.
/// Exported under the `internals` feature only.
///
/// ## WARNING
///
/// This type is volatile and may change.
#[derive(Debug, PartialEq, Clone)]
pub enum Token {
/// An `INT` constant.
IntegerConstant(INT),
/// A `FLOAT` constaint.
///
/// Never appears under the `no_float` feature.
#[cfg(not(feature = "no_float"))]
FloatConstant(FLOAT),
/// An identifier.
Identifier(String),
/// A character constant.
CharConstant(char),
/// A string constant.
StringConstant(String),
/// `{`
LeftBrace,
/// `}`
RightBrace,
/// `(`
LeftParen,
/// `)`
RightParen,
/// `[`
LeftBracket,
/// `]`
RightBracket,
/// `+`
Plus,
/// `+` (unary)
UnaryPlus,
/// `-`
Minus,
/// `-` (unary)
UnaryMinus,
/// `*`
Multiply,
/// `/`
Divide,
/// `%`
Modulo,
/// `~`
PowerOf,
/// `<<`
LeftShift,
/// `>>`
RightShift,
/// `;`
SemiColon,
/// `:`
Colon,
/// `::`
DoubleColon,
/// `,`
Comma,
/// `.`
Period,
/// `#{`
MapStart,
/// `=`
Equals,
/// `true`
True,
/// `false`
False,
/// `let`
Let,
/// `const`
Const,
/// `if`
If,
/// `else`
Else,
/// `while`
While,
/// `loop`
Loop,
/// `for`
For,
/// `in`
In,
/// `<`
LessThan,
/// `>`
GreaterThan,
/// `<=`
LessThanEqualsTo,
/// `>=`
GreaterThanEqualsTo,
/// `==`
EqualsTo,
/// `!=`
NotEqualsTo,
/// `!`
Bang,
/// `|`
Pipe,
/// `||`
Or,
/// `^`
XOr,
/// `&`
Ampersand,
/// `&&`
And,
/// `fn`
///
/// Never appears under the `no_function` feature.
#[cfg(not(feature = "no_function"))]
Fn,
/// `continue`
Continue,
/// `break`
Break,
/// `return`
Return,
/// `throw`
Throw,
/// `+=`
PlusAssign,
/// `-=`
MinusAssign,
/// `*=`
MultiplyAssign,
/// `/=`
DivideAssign,
/// `<<=`
LeftShiftAssign,
/// `>>=`
RightShiftAssign,
/// `&=`
AndAssign,
/// `|=`
OrAssign,
/// `^=`
XOrAssign,
/// `%=`
ModuloAssign,
/// `~=`
PowerOfAssign,
/// `private`
///
/// Never appears under the `no_function` feature.
#[cfg(not(feature = "no_function"))]
Private,
/// `import`
///
/// Never appears under the `no_module` feature.
#[cfg(not(feature = "no_module"))]
Import,
/// `export`
///
/// Never appears under the `no_module` feature.
#[cfg(not(feature = "no_module"))]
Export,
/// `as`
///
/// Never appears under the `no_module` feature.
#[cfg(not(feature = "no_module"))]
As,
/// A lexer error.
LexError(Box<LexError>),
/// A comment block.
Comment(String),
/// A reserved symbol.
Reserved(String),
/// A custom keyword.
Custom(String),
/// End of the input stream.
EOF,
}
@@ -566,7 +658,7 @@ impl Token {
}
}
/// Is this token a reserved keyword?
/// Is this token a reserved symbol?
pub fn is_reserved(&self) -> bool {
match self {
Self::Reserved(_) => true,
@@ -589,7 +681,12 @@ impl From<Token> for String {
}
}
/// State of the tokenizer.
/// [INTERNALS] State of the tokenizer.
/// Exported under the `internals` feature only.
///
/// ## WARNING
///
/// This type is volatile and may change.
#[derive(Debug, Clone, Eq, PartialEq, Default)]
pub struct TokenizeState {
/// Maximum length of a string (0 = unlimited).
@@ -604,7 +701,12 @@ pub struct TokenizeState {
pub include_comments: bool,
}
/// Trait that encapsulates a peekable character input stream.
/// [INTERNALS] Trait that encapsulates a peekable character input stream.
/// Exported under the `internals` feature only.
///
/// ## WARNING
///
/// This trait is volatile and may change.
pub trait InputStream {
/// Get the next character
fn get_next(&mut self) -> Option<char>;
@@ -628,7 +730,12 @@ pub fn is_valid_identifier(name: impl Iterator<Item = char>) -> bool {
first_alphabetic
}
/// Parse a string literal wrapped by `enclosing_char`.
/// [INTERNALS] Parse a string literal wrapped by `enclosing_char`.
/// Exported under the `internals` feature only.
///
/// ## WARNING
///
/// This type is volatile and may change.
pub fn parse_string_literal(
stream: &mut impl InputStream,
state: &mut TokenizeState,
@@ -794,7 +901,12 @@ fn scan_comment(
}
}
/// Get the next token.
/// [INTERNALS] Get the next token from the `InputStream`.
/// Exported under the `internals` feature only.
///
/// ## WARNING
///
/// This type is volatile and may change.
pub fn get_next_token(
stream: &mut impl InputStream,
state: &mut TokenizeState,
@@ -810,6 +922,32 @@ pub fn get_next_token(
result
}
/// Test if the given character is a hex character.
fn is_hex_char(c: char) -> bool {
match c {
'a'..='f' => true,
'A'..='F' => true,
'0'..='9' => true,
_ => false,
}
}
/// Test if the given character is an octal character.
fn is_octal_char(c: char) -> bool {
match c {
'0'..='7' => true,
_ => false,
}
}
/// Test if the given character is a binary character.
fn is_binary_char(c: char) -> bool {
match c {
'0' | '1' => true,
_ => false,
}
}
/// Get the next token.
fn get_next_token_inner(
stream: &mut impl InputStream,
@@ -872,18 +1010,9 @@ fn get_next_token_inner(
eat_next(stream, pos);
let valid = match ch {
'x' | 'X' => [
'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '_',
],
'o' | 'O' => [
'0', '1', '2', '3', '4', '5', '6', '7', '_', '_', '_', '_',
'_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_',
],
'b' | 'B' => [
'0', '1', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_',
'_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_',
],
'x' | 'X' => is_hex_char,
'o' | 'O' => is_octal_char,
'b' | 'B' => is_binary_char,
_ => unreachable!(),
};
@@ -895,7 +1024,7 @@ fn get_next_token_inner(
});
while let Some(next_char_in_escape_seq) = stream.peek_next() {
if !valid.contains(&next_char_in_escape_seq) {
if !valid(next_char_in_escape_seq) {
break;
}

View File

@@ -92,9 +92,12 @@ pub fn calc_fn_spec<'a>(
s.finish()
}
/// A type to hold a number of values in static storage for no-allocation, quick access.
/// [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.
///
@@ -130,6 +133,10 @@ pub fn calc_fn_spec<'a>(
/// # 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<T> {