Move FloatWrapper into types.
This commit is contained in:
parent
ae1e19c98a
commit
ad018aaae3
126
src/ast/expr.rs
126
src/ast/expr.rs
@ -20,16 +20,6 @@ use std::{
|
||||
num::{NonZeroU64, NonZeroU8, NonZeroUsize},
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
use std::{
|
||||
hash::Hasher,
|
||||
ops::{Deref, DerefMut},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
use num_traits::float::FloatCore as Float;
|
||||
|
||||
/// _(internals)_ A binary expression.
|
||||
/// Exported under the `internals` feature only.
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
@ -273,120 +263,6 @@ impl FnCallExpr {
|
||||
}
|
||||
}
|
||||
|
||||
/// A type that wraps a floating-point number and implements [`Hash`].
|
||||
///
|
||||
/// Not available under `no_float`.
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
#[derive(Clone, Copy, PartialEq, PartialOrd)]
|
||||
pub struct FloatWrapper<F>(F);
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl Hash for FloatWrapper<crate::FLOAT> {
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.0.to_ne_bytes().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl<F: Float> AsRef<F> for FloatWrapper<F> {
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
fn as_ref(&self) -> &F {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl<F: Float> AsMut<F> for FloatWrapper<F> {
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
fn as_mut(&mut self) -> &mut F {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl<F: Float> Deref for FloatWrapper<F> {
|
||||
type Target = F;
|
||||
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl<F: Float> DerefMut for FloatWrapper<F> {
|
||||
#[inline(always)]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl<F: Float + fmt::Debug> fmt::Debug for FloatWrapper<F> {
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl<F: Float + fmt::Display + fmt::LowerExp + From<f32>> fmt::Display for FloatWrapper<F> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let abs = self.0.abs();
|
||||
if abs.is_zero() {
|
||||
f.write_str("0.0")
|
||||
} else if abs > Self::MAX_NATURAL_FLOAT_FOR_DISPLAY.into()
|
||||
|| abs < Self::MIN_NATURAL_FLOAT_FOR_DISPLAY.into()
|
||||
{
|
||||
write!(f, "{:e}", self.0)
|
||||
} else {
|
||||
fmt::Display::fmt(&self.0, f)?;
|
||||
if abs.fract().is_zero() {
|
||||
f.write_str(".0")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl<F: Float> From<F> for FloatWrapper<F> {
|
||||
#[inline(always)]
|
||||
fn from(value: F) -> Self {
|
||||
Self::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl<F: Float + FromStr> FromStr for FloatWrapper<F> {
|
||||
type Err = <F as FromStr>::Err;
|
||||
|
||||
#[inline]
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
F::from_str(s).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl<F: Float> FloatWrapper<F> {
|
||||
/// Maximum floating-point number for natural display before switching to scientific notation.
|
||||
pub const MAX_NATURAL_FLOAT_FOR_DISPLAY: f32 = 10_000_000_000_000.0;
|
||||
|
||||
/// Minimum floating-point number for natural display before switching to scientific notation.
|
||||
pub const MIN_NATURAL_FLOAT_FOR_DISPLAY: f32 = 0.000_000_000_000_1;
|
||||
|
||||
/// Create a new [`FloatWrapper`].
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub const fn new(value: F) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
/// _(internals)_ An expression sub-tree.
|
||||
/// Exported under the `internals` feature only.
|
||||
#[derive(Clone, Hash)]
|
||||
@ -405,7 +281,7 @@ pub enum Expr {
|
||||
IntegerConstant(INT, Position),
|
||||
/// Floating-point constant.
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
FloatConstant(FloatWrapper<crate::FLOAT>, Position),
|
||||
FloatConstant(crate::types::FloatWrapper<crate::FLOAT>, Position),
|
||||
/// Character constant.
|
||||
CharConstant(char, Position),
|
||||
/// [String][ImmutableString] constant.
|
||||
|
@ -26,9 +26,6 @@ pub use stmt::{
|
||||
SwitchCasesCollection, TryCatchBlock,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
pub use expr::FloatWrapper;
|
||||
|
||||
/// _(internals)_ Placeholder for a script-defined function.
|
||||
/// Exported under the `internals` feature only.
|
||||
#[cfg(feature = "no_function")]
|
||||
|
@ -9,11 +9,11 @@ use std::{
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
// Calculate an offset+len pair given an actual length of the underlying array.
|
||||
//
|
||||
// Negative starting positions count from the end.
|
||||
//
|
||||
// Values going over bounds are limited to the actual length.
|
||||
/// Calculate an offset+len pair given an actual length of the underlying array.
|
||||
///
|
||||
/// Negative starting positions count from the end.
|
||||
///
|
||||
/// Values going over bounds are limited to the actual length.
|
||||
#[inline]
|
||||
#[allow(dead_code)]
|
||||
pub fn calc_offset_len(length: usize, start: crate::INT, len: crate::INT) -> (usize, usize) {
|
||||
@ -41,11 +41,11 @@ pub fn calc_offset_len(length: usize, start: crate::INT, len: crate::INT) -> (us
|
||||
(start, len)
|
||||
}
|
||||
|
||||
// Calculate an offset+len pair given an actual length of the underlying array.
|
||||
//
|
||||
// Negative starting positions count from the end.
|
||||
//
|
||||
// Values going over bounds call the provided closure to return a default value or an error.
|
||||
/// Calculate an offset+len pair given an actual length of the underlying array.
|
||||
///
|
||||
/// Negative starting positions count from the end.
|
||||
///
|
||||
/// Values going over bounds call the provided closure to return a default value or an error.
|
||||
#[inline]
|
||||
#[allow(dead_code)]
|
||||
pub fn calc_index<E>(
|
||||
|
@ -299,6 +299,10 @@ pub type OptimizationLevel = ();
|
||||
#[cfg(feature = "internals")]
|
||||
pub use types::dynamic::{AccessMode, DynamicReadLock, DynamicWriteLock, Variant};
|
||||
|
||||
#[cfg(feature = "internals")]
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
pub use types::FloatWrapper;
|
||||
|
||||
#[cfg(feature = "internals")]
|
||||
pub use tokenizer::{get_next_token, parse_string_literal};
|
||||
|
||||
@ -333,10 +337,6 @@ pub use ast::Namespace;
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
pub use ast::EncapsulatedEnviron;
|
||||
|
||||
#[cfg(feature = "internals")]
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
pub use ast::FloatWrapper;
|
||||
|
||||
#[cfg(feature = "internals")]
|
||||
pub use eval::{Caches, FnResolutionCache, FnResolutionCacheEntry, GlobalRuntimeState};
|
||||
|
||||
|
@ -134,26 +134,26 @@ mod print_debug_functions {
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
#[rhai_fn(name = "print", name = "to_string")]
|
||||
pub fn print_f64(number: f64) -> ImmutableString {
|
||||
crate::ast::FloatWrapper::new(number).to_string().into()
|
||||
crate::types::FloatWrapper::new(number).to_string().into()
|
||||
}
|
||||
/// Convert the value of `number` into a string.
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
#[rhai_fn(name = "print", name = "to_string")]
|
||||
pub fn print_f32(number: f32) -> ImmutableString {
|
||||
crate::ast::FloatWrapper::new(number).to_string().into()
|
||||
crate::types::FloatWrapper::new(number).to_string().into()
|
||||
}
|
||||
/// Convert the value of `number` into a string.
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
#[rhai_fn(name = "debug", name = "to_debug")]
|
||||
pub fn debug_f64(number: f64) -> ImmutableString {
|
||||
let number = crate::ast::FloatWrapper::new(number);
|
||||
let number = crate::types::FloatWrapper::new(number);
|
||||
format!("{number:?}").into()
|
||||
}
|
||||
/// Convert the value of `number` into a string.
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
#[rhai_fn(name = "debug", name = "to_debug")]
|
||||
pub fn debug_f32(number: f32) -> ImmutableString {
|
||||
let number = crate::ast::FloatWrapper::new(number);
|
||||
let number = crate::types::FloatWrapper::new(number);
|
||||
format!("{number:?}").into()
|
||||
}
|
||||
|
||||
|
@ -382,7 +382,7 @@ pub enum Token {
|
||||
///
|
||||
/// Reserved under the `no_float` feature.
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
FloatConstant(crate::ast::FloatWrapper<crate::FLOAT>),
|
||||
FloatConstant(crate::types::FloatWrapper<crate::FLOAT>),
|
||||
/// A [`Decimal`][rust_decimal::Decimal] constant.
|
||||
///
|
||||
/// Requires the `decimal` feature.
|
||||
@ -1682,7 +1682,7 @@ fn get_next_token_inner(
|
||||
// If integer parsing is unnecessary, try float instead
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
let num = num.or_else(|_| {
|
||||
crate::ast::FloatWrapper::from_str(&result).map(Token::FloatConstant)
|
||||
crate::types::FloatWrapper::from_str(&result).map(Token::FloatConstant)
|
||||
});
|
||||
|
||||
// Then try decimal
|
||||
|
@ -70,7 +70,7 @@ pub enum Union {
|
||||
Int(INT, Tag, AccessMode),
|
||||
/// A floating-point value.
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
Float(crate::ast::FloatWrapper<crate::FLOAT>, Tag, AccessMode),
|
||||
Float(super::FloatWrapper<crate::FLOAT>, Tag, AccessMode),
|
||||
/// _(decimal)_ A fixed-precision decimal value.
|
||||
/// Exported under the `decimal` feature only.
|
||||
#[cfg(feature = "decimal")]
|
||||
@ -867,7 +867,7 @@ impl Dynamic {
|
||||
#[must_use]
|
||||
pub const fn from_float(value: crate::FLOAT) -> Self {
|
||||
Self(Union::Float(
|
||||
crate::ast::FloatWrapper::new(value),
|
||||
super::FloatWrapper::new(value),
|
||||
DEFAULT_TAG_VALUE,
|
||||
ReadWrite,
|
||||
))
|
||||
@ -1859,9 +1859,9 @@ impl From<crate::FLOAT> for Dynamic {
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl From<crate::ast::FloatWrapper<crate::FLOAT>> for Dynamic {
|
||||
impl From<super::FloatWrapper<crate::FLOAT>> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: crate::ast::FloatWrapper<crate::FLOAT>) -> Self {
|
||||
fn from(value: super::FloatWrapper<crate::FLOAT>) -> Self {
|
||||
Self(Union::Float(value, DEFAULT_TAG_VALUE, ReadWrite))
|
||||
}
|
||||
}
|
||||
|
115
src/types/float.rs
Normal file
115
src/types/float.rs
Normal file
@ -0,0 +1,115 @@
|
||||
#![cfg(not(feature = "no_float"))]
|
||||
|
||||
#[cfg(feature = "no_std")]
|
||||
use std::prelude::v1::*;
|
||||
use std::{
|
||||
fmt,
|
||||
hash::{Hash, Hasher},
|
||||
ops::{Deref, DerefMut},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use num_traits::float::FloatCore as Float;
|
||||
|
||||
/// A type that wraps a floating-point number and implements [`Hash`].
|
||||
///
|
||||
/// Not available under `no_float`.
|
||||
#[derive(Clone, Copy, PartialEq, PartialOrd)]
|
||||
pub struct FloatWrapper<F>(F);
|
||||
|
||||
impl Hash for FloatWrapper<crate::FLOAT> {
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.0.to_ne_bytes().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Float> AsRef<F> for FloatWrapper<F> {
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
fn as_ref(&self) -> &F {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Float> AsMut<F> for FloatWrapper<F> {
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
fn as_mut(&mut self) -> &mut F {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Float> Deref for FloatWrapper<F> {
|
||||
type Target = F;
|
||||
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Float> DerefMut for FloatWrapper<F> {
|
||||
#[inline(always)]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Float + fmt::Debug> fmt::Debug for FloatWrapper<F> {
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Float + fmt::Display + fmt::LowerExp + From<f32>> fmt::Display for FloatWrapper<F> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let abs = self.0.abs();
|
||||
if abs.is_zero() {
|
||||
f.write_str("0.0")
|
||||
} else if abs > Self::MAX_NATURAL_FLOAT_FOR_DISPLAY.into()
|
||||
|| abs < Self::MIN_NATURAL_FLOAT_FOR_DISPLAY.into()
|
||||
{
|
||||
write!(f, "{:e}", self.0)
|
||||
} else {
|
||||
fmt::Display::fmt(&self.0, f)?;
|
||||
if abs.fract().is_zero() {
|
||||
f.write_str(".0")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Float> From<F> for FloatWrapper<F> {
|
||||
#[inline(always)]
|
||||
fn from(value: F) -> Self {
|
||||
Self::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Float + FromStr> FromStr for FloatWrapper<F> {
|
||||
type Err = <F as FromStr>::Err;
|
||||
|
||||
#[inline]
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
F::from_str(s).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Float> FloatWrapper<F> {
|
||||
/// Maximum floating-point number for natural display before switching to scientific notation.
|
||||
pub const MAX_NATURAL_FLOAT_FOR_DISPLAY: f32 = 10_000_000_000_000.0;
|
||||
|
||||
/// Minimum floating-point number for natural display before switching to scientific notation.
|
||||
pub const MIN_NATURAL_FLOAT_FOR_DISPLAY: f32 = 0.000_000_000_000_1;
|
||||
|
||||
/// Create a new [`FloatWrapper`].
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub const fn new(value: F) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ pub mod bloom_filter;
|
||||
pub mod custom_types;
|
||||
pub mod dynamic;
|
||||
pub mod error;
|
||||
pub mod float;
|
||||
pub mod fn_ptr;
|
||||
pub mod immutable_string;
|
||||
pub mod interner;
|
||||
@ -18,6 +19,8 @@ pub use dynamic::Dynamic;
|
||||
#[cfg(not(feature = "no_time"))]
|
||||
pub use dynamic::Instant;
|
||||
pub use error::EvalAltResult;
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
pub use float::FloatWrapper;
|
||||
pub use fn_ptr::FnPtr;
|
||||
pub use immutable_string::ImmutableString;
|
||||
pub use interner::StringsInterner;
|
||||
|
Loading…
Reference in New Issue
Block a user