Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
//! This module provides cached instances of frequently used Number values
//! to reduce allocations in hot paths.

#[cfg(feature = "decimal")]
use std::sync::Arc;

#[cfg(feature = "decimal")]
use rust_decimal::Decimal;

#[cfg(feature = "decimal")]
use crate::decimal_pool::create_decimal_arc;
use crate::float::Float64;
use crate::types::Number;

Expand Down Expand Up @@ -69,9 +68,9 @@ define_common_numbers! {

// Decimal constants (when feature enabled)
#[cfg(feature = "decimal")]
decimal_zero: Decimal(Arc::new(Decimal::ZERO)),
decimal_zero: Decimal(create_decimal_arc(Decimal::ZERO)),
#[cfg(feature = "decimal")]
decimal_one: Decimal(Arc::new(Decimal::ONE)),
decimal_one: Decimal(create_decimal_arc(Decimal::ONE)),
}

/// Get cached zero value for a given type based on a reference Number
Expand Down
7 changes: 3 additions & 4 deletions src/conversions/from_impls.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
//! From trait implementations for converting to Number.

#[cfg(feature = "decimal")]
use std::sync::Arc;

#[cfg(feature = "decimal")]
use rust_decimal::Decimal;

#[cfg(feature = "decimal")]
use crate::decimal_pool::create_decimal_arc;
use crate::{Float64, Number};

// Generate From trait implementations for integer types using macro
Expand Down Expand Up @@ -63,7 +62,7 @@ impl From<f64> for Number {
#[cfg(feature = "decimal")]
impl From<Decimal> for Number {
fn from(n: Decimal) -> Self {
Self::Decimal(Arc::new(n))
Self::Decimal(create_decimal_arc(n))
}
}

Expand Down
61 changes: 39 additions & 22 deletions src/conversions/parsing.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
//! String parsing utilities and implementations.

use std::borrow::Cow;
use std::convert::TryFrom;
#[cfg(feature = "decimal")]
use std::sync::Arc;

#[cfg(feature = "decimal")]
use rust_decimal::Decimal;

use super::errors::ParseNumberError;
#[cfg(feature = "decimal")]
use crate::decimal_pool::create_decimal_arc;
use crate::{Float64, Number};

#[inline]
Expand All @@ -24,21 +25,32 @@ fn validate_underscores(s: &str) -> bool {
return true;
}

let is_hex = bytes.len() >= 2 && bytes[0] == b'0' && (bytes[1] | 32) == b'x';
let (offset, bytes_without_sign) = if matches!(bytes.first(), Some(b'+' | b'-')) {
(1, &bytes[1..])
} else {
(0, bytes)
};

let is_hex = bytes_without_sign.len() >= 2
&& bytes_without_sign[0] == b'0'
&& (bytes_without_sign[1] | 32) == b'x';
let has_scientific = if is_hex {
s.bytes().any(|b| (b | 32) == b'p')
bytes_without_sign.iter().any(|&b| (b | 32) == b'p')
} else {
s.bytes().any(|b| (b | 32) == b'e')
bytes_without_sign.iter().any(|&b| (b | 32) == b'e')
};

let e_pos_opt = if has_scientific {
bytes.iter().position(|&b| {
if is_hex {
(b | 32) == b'p'
} else {
(b | 32) == b'e'
}
})
bytes_without_sign
.iter()
.position(|&b| {
if is_hex {
(b | 32) == b'p'
} else {
(b | 32) == b'e'
}
})
.map(|pos| pos + offset)
} else {
None
};
Expand Down Expand Up @@ -79,11 +91,15 @@ fn validate_underscores(s: &str) -> bool {

#[inline]
#[must_use]
fn remove_valid_underscores(s: &str) -> Option<String> {
fn remove_valid_underscores(s: &str) -> Option<Cow<'_, str>> {
if !validate_underscores(s) {
return None;
}
Some(s.replace('_', ""))
if s.contains('_') {
Some(Cow::Owned(s.replace('_', "")))
} else {
Some(Cow::Borrowed(s))
}
}

#[inline]
Expand Down Expand Up @@ -123,7 +139,7 @@ fn parse_unsigned_u128(input: &str) -> Option<u128> {
}

let s = remove_valid_underscores(s)?;
let (base, digits) = detect_base_and_digits(&s);
let (base, digits) = detect_base_and_digits(s.as_ref());
if digits.is_empty() {
return None;
}
Expand All @@ -146,7 +162,7 @@ fn parse_signed_i128(input: &str) -> Option<i128> {
}

let s = remove_valid_underscores(s)?;
let (base, digits) = detect_base_and_digits(&s);
let (base, digits) = detect_base_and_digits(s.as_ref());
if digits.is_empty() {
return None;
}
Expand Down Expand Up @@ -238,20 +254,21 @@ impl TryFrom<&str> for Number {
let Some(sanitized) = remove_valid_underscores(trimmed) else {
return Err(ParseNumberError::InvalidFormat(trimmed.to_string()));
};
let has_decimal = sanitized.contains('.');
let sanitized_str = sanitized.as_ref();
let has_decimal = sanitized_str.contains('.');

if !has_decimal
&& let Some(result) =
try_parse_integer_with_promotion(&sanitized, trimmed.starts_with('-'))
try_parse_integer_with_promotion(sanitized_str, trimmed.starts_with('-'))
{
return result;
}

if let Ok(n) = sanitized.parse::<f64>() {
if let Ok(n) = sanitized_str.parse::<f64>() {
#[cfg(feature = "decimal")]
{
if let Ok(decimal) = sanitized.parse::<Decimal>() {
return Ok(Self::Decimal(Arc::new(decimal)));
if let Ok(decimal) = sanitized_str.parse::<Decimal>() {
return Ok(Self::Decimal(create_decimal_arc(decimal)));
}

if n.is_finite()
Expand All @@ -260,7 +277,7 @@ impl TryFrom<&str> for Number {
&& n.abs() < 1e28
&& let Ok(decimal) = rust_decimal::Decimal::try_from(n)
{
return Ok(Self::Decimal(Arc::new(decimal)));
return Ok(Self::Decimal(create_decimal_arc(decimal)));
}

return Ok(Self::F64(Float64(n)));
Expand Down
Loading