diff --git a/src/api/limits.rs b/src/api/limits.rs index 5191f2e9..6754edb2 100644 --- a/src/api/limits.rs +++ b/src/api/limits.rs @@ -6,23 +6,20 @@ use std::num::{NonZeroU64, NonZeroUsize}; #[cfg(feature = "no_std")] use std::prelude::v1::*; +#[cfg(debug_assertions)] pub mod default_limits { - #[cfg(debug_assertions)] #[cfg(not(feature = "no_function"))] pub const MAX_CALL_STACK_DEPTH: usize = 8; - #[cfg(debug_assertions)] pub const MAX_EXPR_DEPTH: usize = 32; #[cfg(not(feature = "no_function"))] - #[cfg(debug_assertions)] pub const MAX_FUNCTION_EXPR_DEPTH: usize = 16; - - #[cfg(not(debug_assertions))] +} +#[cfg(not(debug_assertions))] +pub mod default_limits { #[cfg(not(feature = "no_function"))] pub const MAX_CALL_STACK_DEPTH: usize = 64; - #[cfg(not(debug_assertions))] pub const MAX_EXPR_DEPTH: usize = 64; #[cfg(not(feature = "no_function"))] - #[cfg(not(debug_assertions))] pub const MAX_FUNCTION_EXPR_DEPTH: usize = 32; } @@ -55,7 +52,7 @@ pub struct Limits { #[cfg(not(feature = "no_module"))] pub max_modules: usize, /// Maximum length of a [string][crate::ImmutableString]. - pub max_string_size: Option, + pub max_string_len: Option, /// Maximum length of an [array][crate::Array]. /// /// Not available under `no_index`. @@ -83,7 +80,7 @@ impl Limits { max_operations: None, #[cfg(not(feature = "no_module"))] max_modules: usize::MAX, - max_string_size: None, + max_string_len: None, #[cfg(not(feature = "no_index"))] max_array_size: None, #[cfg(not(feature = "no_object"))] @@ -104,7 +101,7 @@ impl Engine { /// Is there a data size limit set? #[inline(always)] pub(crate) const fn has_data_size_limit(&self) -> bool { - self.limits.max_string_size.is_some() + self.limits.max_string_len.is_some() || { #[cfg(not(feature = "no_index"))] { @@ -222,19 +219,19 @@ impl Engine { #[cfg(feature = "no_function")] return 0; } - /// Set the maximum length of [strings][crate::ImmutableString] (0 for unlimited). + /// Set the maximum length, in bytes, of [strings][crate::ImmutableString] (0 for unlimited). /// /// Not available under `unchecked`. #[inline(always)] - pub fn set_max_string_size(&mut self, max_size: usize) -> &mut Self { - self.limits.max_string_size = NonZeroUsize::new(max_size); + pub fn set_max_string_size(&mut self, max_len: usize) -> &mut Self { + self.limits.max_string_len = NonZeroUsize::new(max_len); self } - /// The maximum length of [strings][crate::ImmutableString] (0 for unlimited). + /// The maximum length, in bytes, of [strings][crate::ImmutableString] (0 for unlimited). #[inline] #[must_use] pub const fn max_string_size(&self) -> usize { - match self.limits.max_string_size { + match self.limits.max_string_len { Some(n) => n.get(), None => 0, } diff --git a/src/api/limits_unchecked.rs b/src/api/limits_unchecked.rs index 02179ecc..975162c4 100644 --- a/src/api/limits_unchecked.rs +++ b/src/api/limits_unchecked.rs @@ -1,3 +1,4 @@ +//! Placeholder settings for [`Engine`]'s limitations. #![cfg(feature = "unchecked")] use crate::Engine; @@ -5,7 +6,7 @@ use crate::Engine; impl Engine { /// The maximum levels of function calls allowed for a script. /// - /// Always returns [`usize::MAX`] under `unchecked`. + /// Always returns [`usize::MAX`]. #[inline(always)] #[must_use] pub const fn max_call_levels(&self) -> usize { @@ -13,7 +14,7 @@ impl Engine { } /// The maximum number of operations allowed for a script to run (0 for unlimited). /// - /// Always returns zero under `unchecked`. + /// Always returns zero. #[inline(always)] #[must_use] pub const fn max_operations(&self) -> u64 { @@ -21,7 +22,7 @@ impl Engine { } /// The maximum number of imported [modules][crate::Module] allowed for a script. /// - /// Always returns [`usize::MAX`] under `unchecked`. + /// Always returns [`usize::MAX`]. #[inline(always)] #[must_use] pub const fn max_modules(&self) -> usize { @@ -29,7 +30,7 @@ impl Engine { } /// The depth limit for expressions (0 for unlimited). /// - /// Always returns zero under `unchecked`. + /// Always returns zero. #[inline(always)] #[must_use] pub const fn max_expr_depth(&self) -> usize { @@ -37,7 +38,7 @@ impl Engine { } /// The depth limit for expressions in functions (0 for unlimited). /// - /// Always returns zero under `unchecked`. + /// Always returns zero. #[inline(always)] #[must_use] pub const fn max_function_expr_depth(&self) -> usize { @@ -45,7 +46,7 @@ impl Engine { } /// The maximum length of [strings][crate::ImmutableString] (0 for unlimited). /// - /// Always returns zero under `unchecked`. + /// Always returns zero. #[inline(always)] #[must_use] pub const fn max_string_size(&self) -> usize { @@ -53,7 +54,7 @@ impl Engine { } /// The maximum length of [arrays][crate::Array] (0 for unlimited). /// - /// Always returns zero under `unchecked`. + /// Always returns zero. #[inline(always)] #[must_use] pub const fn max_array_size(&self) -> usize { @@ -61,7 +62,7 @@ impl Engine { } /// The maximum size of [object maps][crate::Map] (0 for unlimited). /// - /// Always returns zero under `unchecked`. + /// Always returns zero. #[inline(always)] #[must_use] pub const fn max_map_size(&self) -> usize { diff --git a/src/eval/data_check.rs b/src/eval/data_check.rs index cf6c8ece..fc1948fc 100644 --- a/src/eval/data_check.rs +++ b/src/eval/data_check.rs @@ -80,7 +80,7 @@ impl Engine { ) -> RhaiResultOf<()> { if self .limits - .max_string_size + .max_string_len .map_or(false, |max| s > max.get()) { return Err( diff --git a/src/eval/stmt.rs b/src/eval/stmt.rs index 13f53334..144df5d2 100644 --- a/src/eval/stmt.rs +++ b/src/eval/stmt.rs @@ -501,21 +501,23 @@ impl Engine { // 2) Global modules - packages // 3) Imported modules - functions marked with global namespace // 4) Global sub-modules - functions marked with global namespace - let func = self + let iter_func = self .global_modules .iter() .find_map(|m| m.get_iter(iter_type)); #[cfg(not(feature = "no_module"))] - let func = func.or_else(|| global.get_iter(iter_type)).or_else(|| { - self.global_sub_modules - .as_deref() - .into_iter() - .flatten() - .find_map(|(_, m)| m.get_qualified_iter(iter_type)) - }); + let iter_func = iter_func + .or_else(|| global.get_iter(iter_type)) + .or_else(|| { + self.global_sub_modules + .as_deref() + .into_iter() + .flatten() + .find_map(|(_, m)| m.get_qualified_iter(iter_type)) + }); - let func = func.ok_or_else(|| ERR::ErrorFor(expr.start_position()))?; + let iter_func = iter_func.ok_or_else(|| ERR::ErrorFor(expr.start_position()))?; // Restore scope at end of statement let orig_scope_len = scope.len(); @@ -536,7 +538,7 @@ impl Engine { let mut result = Dynamic::UNIT; - for (x, iter_value) in func(iter_obj).enumerate() { + for (x, iter_value) in iter_func(iter_obj).enumerate() { // Increment counter if counter_index < usize::MAX { // As the variable increments from 0, this should always work @@ -604,10 +606,7 @@ impl Engine { Stmt::TryCatch(x, ..) => { let TryCatchBlock { try_block, - catch_var: - Ident { - name: catch_var, .. - }, + catch_var, catch_block, } = &**x; @@ -659,7 +658,7 @@ impl Engine { }); if !catch_var.is_empty() { - scope.push(catch_var.clone(), err_value); + scope.push(catch_var.name.clone(), err_value); } self.eval_stmt_block(global, caches, scope, this_ptr, catch_block, true) @@ -768,7 +767,7 @@ impl Engine { #[cfg(not(feature = "no_module"))] if let Some(alias) = _alias { - scope.add_alias_by_index(scope.len() - 1, alias.name.as_str().into()); + scope.add_alias_by_index(scope.len() - 1, alias.as_str().into()); } Ok(Dynamic::UNIT) diff --git a/src/eval/target.rs b/src/eval/target.rs index 1f36a835..e1980d1b 100644 --- a/src/eval/target.rs +++ b/src/eval/target.rs @@ -186,6 +186,7 @@ impl<'a> Target<'a> { Self::RefMut(r) => r.is_shared(), Self::SharedValue { .. } => true, Self::TempValue(value) => value.is_shared(), + #[cfg(not(feature = "no_index"))] Self::Bit { .. } | Self::BitField { .. } | Self::BlobByte { .. } diff --git a/src/func/callable_function.rs b/src/func/callable_function.rs index 4d441e63..aad705c9 100644 --- a/src/func/callable_function.rs +++ b/src/func/callable_function.rs @@ -204,16 +204,16 @@ impl CallableFunction { #[cfg(not(feature = "no_function"))] impl From for CallableFunction { #[inline(always)] - fn from(_func: crate::ast::ScriptFnDef) -> Self { - Self::Script(_func.into()) + fn from(func: crate::ast::ScriptFnDef) -> Self { + Self::Script(func.into()) } } #[cfg(not(feature = "no_function"))] impl From> for CallableFunction { #[inline(always)] - fn from(_func: Shared) -> Self { - Self::Script(_func) + fn from(func: Shared) -> Self { + Self::Script(func) } } diff --git a/src/parser.rs b/src/parser.rs index 2daa3358..ceb1b814 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1464,7 +1464,7 @@ impl Engine { // Restore the strings interner by swapping it back std::mem::swap(state.interned_strings, new_state.interned_strings); - let (expr, func) = result?; + let (expr, f) = result?; #[cfg(not(feature = "no_closure"))] new_state @@ -1490,8 +1490,8 @@ impl Engine { } })?; - let hash_script = calc_fn_hash(None, &func.name, func.params.len()); - lib.insert(hash_script, func.into()); + let hash_script = calc_fn_hash(None, &f.name, f.params.len()); + lib.insert(hash_script, f.into()); expr } @@ -2170,42 +2170,42 @@ impl Engine { )), // lhs.nnn::func(...) - syntax error #[cfg(not(feature = "no_module"))] - (.., Expr::FnCall(func, ..)) if func.is_qualified() => { - Err(PERR::PropertyExpected.into_err(func.namespace.position())) + (.., Expr::FnCall(f, ..)) if f.is_qualified() => { + Err(PERR::PropertyExpected.into_err(f.namespace.position())) } // lhs.Fn() or lhs.eval() - (.., Expr::FnCall(func, func_pos)) - if func.args.is_empty() + (.., Expr::FnCall(f, func_pos)) + if f.args.is_empty() && [crate::engine::KEYWORD_FN_PTR, crate::engine::KEYWORD_EVAL] - .contains(&func.name.as_str()) => + .contains(&f.name.as_str()) => { let err_msg = format!( "'{}' should not be called in method style. Try {}(...);", - func.name, func.name + f.name, f.name ); - Err(LexError::ImproperSymbol(func.name.to_string(), err_msg).into_err(func_pos)) + Err(LexError::ImproperSymbol(f.name.to_string(), err_msg).into_err(func_pos)) } // lhs.func!(...) - (.., Expr::FnCall(func, func_pos)) if func.capture_parent_scope => { + (.., Expr::FnCall(f, func_pos)) if f.capture_parent_scope => { Err(PERR::MalformedCapture( "method-call style does not support running within the caller's scope".into(), ) .into_err(func_pos)) } // lhs.func(...) - (lhs, Expr::FnCall(mut func, func_pos)) => { + (lhs, Expr::FnCall(mut f, func_pos)) => { // Recalculate hash - func.hashes = if is_valid_function_name(&func.name) { + f.hashes = if is_valid_function_name(&f.name) { FnCallHashes::from_all( #[cfg(not(feature = "no_function"))] - calc_fn_hash(None, &func.name, func.args.len()), - calc_fn_hash(None, &func.name, func.args.len() + 1), + calc_fn_hash(None, &f.name, f.args.len()), + calc_fn_hash(None, &f.name, f.args.len() + 1), ) } else { - FnCallHashes::from_native(calc_fn_hash(None, &func.name, func.args.len() + 1)) + FnCallHashes::from_native(calc_fn_hash(None, &f.name, f.args.len() + 1)) }; - let rhs = Expr::MethodCall(func, func_pos); + let rhs = Expr::MethodCall(f, func_pos); Ok(Expr::Dot(BinaryExpr { lhs, rhs }.into(), op_flags, op_pos)) } // lhs.dot_lhs.dot_rhs or lhs.dot_lhs[idx_rhs] @@ -2224,8 +2224,8 @@ impl Engine { } // lhs.module::func().dot_rhs or lhs.module::func()[idx_rhs] - syntax error #[cfg(not(feature = "no_module"))] - Expr::FnCall(func, ..) if func.is_qualified() => { - Err(PERR::PropertyExpected.into_err(func.namespace.position())) + Expr::FnCall(f, ..) if f.is_qualified() => { + Err(PERR::PropertyExpected.into_err(f.namespace.position())) } // lhs.id.dot_rhs or lhs.id[idx_rhs] Expr::Variable(..) | Expr::Property(..) => { @@ -2243,24 +2243,20 @@ impl Engine { Ok(Expr::Dot(BinaryExpr { lhs, rhs }.into(), op_flags, op_pos)) } // lhs.func().dot_rhs or lhs.func()[idx_rhs] - Expr::FnCall(mut func, func_pos) => { + Expr::FnCall(mut f, func_pos) => { // Recalculate hash - func.hashes = if is_valid_function_name(&func.name) { + f.hashes = if is_valid_function_name(&f.name) { FnCallHashes::from_all( #[cfg(not(feature = "no_function"))] - calc_fn_hash(None, &func.name, func.args.len()), - calc_fn_hash(None, &func.name, func.args.len() + 1), + calc_fn_hash(None, &f.name, f.args.len()), + calc_fn_hash(None, &f.name, f.args.len() + 1), ) } else { - FnCallHashes::from_native(calc_fn_hash( - None, - &func.name, - func.args.len() + 1, - )) + FnCallHashes::from_native(calc_fn_hash(None, &f.name, f.args.len() + 1)) }; let new_lhs = BinaryExpr { - lhs: Expr::MethodCall(func, func_pos), + lhs: Expr::MethodCall(f, func_pos), rhs: x.rhs, } .into(); @@ -3303,7 +3299,7 @@ impl Engine { max_expr_depth: self.max_function_expr_depth(), }; - let func = self.parse_fn( + let f = self.parse_fn( input, new_state, lib, @@ -3312,22 +3308,21 @@ impl Engine { #[cfg(not(feature = "no_function"))] #[cfg(feature = "metadata")] comments, - ); + )?; // Restore parse state - let func = func?; - let hash = calc_fn_hash(None, &func.name, func.params.len()); + let hash = calc_fn_hash(None, &f.name, f.params.len()); if !lib.is_empty() && lib.contains_key(&hash) { return Err(PERR::FnDuplicatedDefinition( - func.name.to_string(), - func.params.len(), + f.name.to_string(), + f.params.len(), ) .into_err(pos)); } - lib.insert(hash, func.into()); + lib.insert(hash, f.into()); Ok(Stmt::Noop(pos)) } diff --git a/src/tokenizer.rs b/src/tokenizer.rs index 7f392ff1..7ef8d7f7 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -852,7 +852,7 @@ impl From for String { #[derive(Debug, Clone, Eq, PartialEq, Default)] pub struct TokenizeState { /// Maximum length of a string. - pub max_string_size: Option, + pub max_string_len: Option, /// Can the next token be a unary operator? pub next_token_cannot_be_unary: bool, /// Shared object to allow controlling the tokenizer externally. @@ -879,6 +879,18 @@ pub trait InputStream { fn peek_next(&mut self) -> Option; } +/// Return error if the string is longer than the maximum length. +#[inline] +fn ensure_string_len_within_limit(max: Option, value: &str) -> Result<(), LexError> { + if let Some(max) = max { + if value.len() > max.get() { + return Err(LexError::StringTooLong(max.get())); + } + } + + Ok(()) +} + /// _(internals)_ Parse a string literal ended by a specified termination character. /// Exported under the `internals` feature only. /// @@ -968,11 +980,8 @@ pub fn parse_string_literal( break; } - if let Some(max) = state.max_string_size { - if result.len() > max.get() { - return Err((LexError::StringTooLong(max.get()), *pos)); - } - } + ensure_string_len_within_limit(state.max_string_len, &result) + .map_err(|err| (err, start))?; // Close wrapper if termination_char == next_char && escape.is_empty() { @@ -1107,11 +1116,7 @@ pub fn parse_string_literal( } } - if let Some(max) = state.max_string_size { - if result.len() > max.get() { - return Err((LexError::StringTooLong(max.get()), *pos)); - } - } + ensure_string_len_within_limit(state.max_string_len, &result).map_err(|err| (err, start))?; Ok((result, interpolated, first_char)) } @@ -1430,11 +1435,17 @@ fn get_next_token_inner( // letter or underscore ... #[cfg(not(feature = "unicode-xid-ident"))] ('a'..='z' | '_' | 'A'..='Z', ..) => { - return Some(get_token_as_identifier(stream, pos, start_pos, c)); + return Some( + parse_identifier_token(stream, pos, start_pos, c) + .unwrap_or_else(|err| (Token::LexError(err.into()), start_pos)), + ); } #[cfg(feature = "unicode-xid-ident")] (ch, ..) if unicode_xid::UnicodeXID::is_xid_start(ch) || ch == '_' => { - return Some(get_token_as_identifier(stream, pos, start_pos, c)); + return Some( + parse_identifier_token(stream, pos, start_pos, c) + .unwrap_or_else(|err| (Token::LexError(err.into()), start_pos)), + ); } // " - string literal @@ -1902,12 +1913,12 @@ fn get_next_token_inner( } /// Get the next token, parsing it as an identifier. -fn get_token_as_identifier( +fn parse_identifier_token( stream: &mut impl InputStream, pos: &mut Position, start_pos: Position, first_char: char, -) -> (Token, Position) { +) -> Result<(Token, Position), LexError> { let mut identifier = SmartString::new_const(); identifier.push(first_char); @@ -1922,19 +1933,20 @@ fn get_token_as_identifier( } if let Some(token) = Token::lookup_symbol_from_syntax(&identifier) { - return (token, start_pos); - } else if Token::is_reserved_keyword(&identifier) { - return (Token::Reserved(Box::new(identifier)), start_pos); + return Ok((token, start_pos)); + } + if Token::is_reserved_keyword(&identifier) { + return Ok((Token::Reserved(Box::new(identifier)), start_pos)); } if !is_valid_identifier(&identifier) { - return ( + return Ok(( Token::LexError(LERR::MalformedIdentifier(identifier.to_string()).into()), start_pos, - ); + )); } - (Token::Identifier(identifier.into()), start_pos) + Ok((Token::Identifier(identifier.into()), start_pos)) } /// Is a keyword allowed as a function? @@ -2236,10 +2248,7 @@ impl Engine { TokenIterator { engine: self, state: TokenizeState { - #[cfg(not(feature = "unchecked"))] - max_string_size: self.limits.max_string_size, - #[cfg(feature = "unchecked")] - max_string_size: None, + max_string_len: NonZeroUsize::new(self.max_string_size()), next_token_cannot_be_unary: false, tokenizer_control: buffer, comment_level: 0, diff --git a/src/types/parse_error.rs b/src/types/parse_error.rs index 1457a1c4..6e29e96f 100644 --- a/src/types/parse_error.rs +++ b/src/types/parse_error.rs @@ -19,7 +19,7 @@ pub enum LexError { UnexpectedInput(String), /// A string literal is not terminated before a new-line or EOF. UnterminatedString, - /// An identifier is in an invalid format. + /// An identifier or string literal is longer than the maximum allowed length. StringTooLong(usize), /// An string/character/numeric escape sequence is in an invalid format. MalformedEscapeSequence(String), @@ -44,11 +44,7 @@ impl fmt::Display for LexError { Self::MalformedChar(s) => write!(f, "Invalid character: '{s}'"), Self::MalformedIdentifier(s) => write!(f, "Variable name is not proper: '{s}'"), Self::UnterminatedString => f.write_str("Open string is not terminated"), - Self::StringTooLong(max) => write!( - f, - "Length of string literal exceeds the maximum limit ({})", - max - ), + Self::StringTooLong(max) => write!(f, "String is too long (max {max})"), Self::ImproperSymbol(s, d) if d.is_empty() => { write!(f, "Invalid symbol encountered: '{s}'") } @@ -262,7 +258,7 @@ impl From for ParseErrorType { fn from(err: LexError) -> Self { match err { LexError::StringTooLong(max) => { - Self::LiteralTooLarge("Length of string literal".to_string(), max) + Self::LiteralTooLarge("Length of string".to_string(), max) } _ => Self::BadInput(err), } diff --git a/src/types/position.rs b/src/types/position.rs index 4284ecb4..2deee226 100644 --- a/src/types/position.rs +++ b/src/types/position.rs @@ -1,3 +1,4 @@ +//! Script character position type. #![cfg(not(feature = "no_position"))] #[cfg(feature = "no_std")] @@ -48,6 +49,8 @@ impl Position { Self { line, pos: _pos } } /// Get the line number (1-based), or [`None`] if there is no position. + /// + /// Always returns [`None`] under `no_position`. #[inline] #[must_use] pub const fn line(self) -> Option { @@ -58,6 +61,8 @@ impl Position { } } /// Get the character position (1-based), or [`None`] if at beginning of a line. + /// + /// Always returns [`None`] under `no_position`. #[inline] #[must_use] pub const fn position(self) -> Option { @@ -100,18 +105,24 @@ impl Position { } } /// Is this [`Position`] at the beginning of a line? + /// + /// Always returns `false` under `no_position`. #[inline] #[must_use] pub const fn is_beginning_of_line(self) -> bool { self.pos == 0 && !self.is_none() } /// Is there no [`Position`]? + /// + /// Always returns `true` under `no_position`. #[inline] #[must_use] pub const fn is_none(self) -> bool { self.line == 0 && self.pos == 0 } /// Returns an fallback [`Position`] if it is [`NONE`][Position::NONE]? + /// + /// Always returns the fallback under `no_position`. #[inline] #[must_use] pub const fn or_else(self, pos: Self) -> Self { @@ -219,18 +230,24 @@ impl Span { Self { start, end } } /// Is this [`Span`] non-existent? + /// + /// Always returns `true` under `no_position`. #[inline] #[must_use] pub const fn is_none(&self) -> bool { self.start.is_none() && self.end.is_none() } /// Get the [`Span`]'s starting [position][Position]. + /// + /// Always returns [`Position::NONE`] under `no_position`. #[inline(always)] #[must_use] pub const fn start(&self) -> Position { self.start } /// Get the [`Span`]'s ending [position][Position]. + /// + /// Always returns [`Position::NONE`] under `no_position`. #[inline(always)] #[must_use] pub const fn end(&self) -> Position { diff --git a/src/types/position_none.rs b/src/types/position_none.rs index 469491b2..c0ced769 100644 --- a/src/types/position_none.rs +++ b/src/types/position_none.rs @@ -1,3 +1,4 @@ +//! Placeholder script character position type. #![cfg(feature = "no_position")] #![allow(unused_variables)] @@ -25,12 +26,16 @@ impl Position { Self } /// Get the line number (1-based), or [`None`] if there is no position. + /// + /// Always returns [`None`]. #[inline(always)] #[must_use] pub const fn line(self) -> Option { None } /// Get the character position (1-based), or [`None`] if at beginning of a line. + /// + /// Always returns [`None`]. #[inline(always)] #[must_use] pub const fn position(self) -> Option { @@ -46,18 +51,24 @@ impl Position { #[inline(always)] pub(crate) fn new_line(&mut self) {} /// Is this [`Position`] at the beginning of a line? + /// + /// Always returns `false`. #[inline(always)] #[must_use] pub const fn is_beginning_of_line(self) -> bool { false } /// Is there no [`Position`]? + /// + /// Always returns `true`. #[inline(always)] #[must_use] pub const fn is_none(self) -> bool { true } /// Returns an fallback [`Position`] if it is [`NONE`][Position::NONE]? + /// + /// Always returns the fallback. #[inline(always)] #[must_use] pub const fn or_else(self, pos: Self) -> Self { @@ -130,22 +141,28 @@ impl Span { Self } /// Is this [`Span`] non-existent? + /// + /// Always returns `true`. #[inline(always)] #[must_use] pub const fn is_none(&self) -> bool { true } /// Get the [`Span`]'s starting [position][Position]. + /// + /// Always returns [`Position::NONE`]. #[inline(always)] #[must_use] pub const fn start(&self) -> Position { - Position + Position::NONE } /// Get the [`Span`]'s ending [position][Position]. + /// + /// Always returns [`Position::NONE`]. #[inline(always)] #[must_use] pub const fn end(&self) -> Position { - Position + Position::NONE } }