Skip to content

Commit aaebc7d

Browse files
committed
Cleanup.
Raw f64 in some more places, use rust std f64 parsing for numbers. Also fix some numeric comparisions and remove a duplicate test.
1 parent 76b6638 commit aaebc7d

File tree

10 files changed

+68
-164
lines changed

10 files changed

+68
-164
lines changed

rsass/src/css/value.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::sass::Function;
66
use crate::value::{Color, ListSeparator, Number, Numeric, Operator};
77

88
/// A css value.
9-
#[derive(Clone, Debug, Eq, PartialOrd)]
9+
#[derive(Clone, Debug, PartialOrd)]
1010
pub enum Value {
1111
/// A special kind of escape. Only really used for !important.
1212
Bang(String),
@@ -311,6 +311,7 @@ impl PartialEq for Value {
311311
}
312312
}
313313
}
314+
impl Eq for Value {}
314315

315316
impl From<bool> for Value {
316317
fn from(v: bool) -> Self {

rsass/src/parser/value.rs

+17-69
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@ use super::{
1010
input_to_string, list_or_single, position, sass_string, PResult, Span,
1111
};
1212
use crate::sass::{BinOp, SassString, Value};
13-
use crate::value::{ListSeparator, Number, Numeric, Operator, Rgba};
13+
use crate::value::{ListSeparator, Numeric, Operator, Rgba};
1414
use nom::branch::alt;
1515
use nom::bytes::complete::{tag, tag_no_case};
1616
use nom::character::complete::{
1717
alphanumeric1, char, digit1, multispace0, multispace1, one_of,
1818
};
1919
use nom::combinator::{
20-
cut, into, map, map_res, not, opt, peek, recognize, success, value,
20+
cut, into, map, map_opt, map_res, not, opt, peek, recognize, value,
2121
verify,
2222
};
2323
use nom::error::context;
24-
use nom::multi::{fold_many0, fold_many1, many0, many_m_n, separated_list1};
24+
use nom::multi::{fold_many0, many0, many_m_n, separated_list1};
2525
use nom::sequence::{delimited, pair, preceded, terminated, tuple};
2626
use std::str::from_utf8;
2727

@@ -332,68 +332,20 @@ pub fn numeric(input: Span) -> PResult<Numeric> {
332332
})(input)
333333
}
334334

335-
pub fn number(input: Span) -> PResult<Number> {
336-
map(
337-
tuple((
338-
sign_neg,
335+
pub fn number(input: Span) -> PResult<f64> {
336+
map_opt(
337+
recognize(delimited(
338+
opt(one_of("+-")),
339339
alt((
340-
map(pair(decimal_integer, decimal_decimals), |(n, d)| n + d),
341-
decimal_decimals,
342-
decimal_integer,
343-
)),
344-
opt(preceded(
345-
alt((tag("e"), tag("E"))),
346-
tuple((sign_neg, decimal_i32)),
340+
terminated(digit1, opt(terminated(char('.'), digit1))),
341+
preceded(char('.'), digit1),
347342
)),
343+
opt(delimited(one_of("eE"), opt(one_of("+-")), digit1)),
348344
)),
349-
|(is_neg, num, exp)| {
350-
let value = if is_neg { -num } else { num };
351-
Number::from(if let Some((e_neg, e_val)) = exp {
352-
let e_val = if e_neg { -e_val } else { e_val };
353-
// Note: powi sounds right, but looses some precision.
354-
value * 10f64.powf(e_val.into())
355-
} else {
356-
value
357-
})
358-
},
359-
)(input)
360-
}
361-
362-
/// Parse true on `-` and false on `+` or no sign.
363-
fn sign_neg(input: Span) -> PResult<bool> {
364-
alt((
365-
value(true, char('-')),
366-
value(false, char('+')),
367-
success(false),
368-
))(input)
369-
}
370-
371-
pub fn decimal_integer(input: Span) -> PResult<f64> {
372-
map(digit1, |s: Span| {
373-
s.fragment()
374-
.iter()
375-
.fold(0.0, |r, d| (r * 10.) + f64::from(d - b'0'))
376-
})(input)
377-
}
378-
pub fn decimal_i32(input: Span) -> PResult<i32> {
379-
fold_many1(
380-
// Note: We should use bytes directly, one_of returns a char.
381-
one_of("0123456789"),
382-
|| 0,
383-
|r, d| (r * 10) + i32::from(d as u8 - b'0'),
345+
|s: Span| from_utf8(s.fragment()).ok()?.parse().ok(),
384346
)(input)
385347
}
386348

387-
pub fn decimal_decimals(input: Span) -> PResult<f64> {
388-
map(preceded(char('.'), digit1), |s: Span| {
389-
let digits = s.fragment();
390-
digits
391-
.iter()
392-
.fold(0.0, |r, d| (r * 10.) + f64::from(d - b'0'))
393-
* (10f64).powf(-(digits.len() as f64))
394-
})(input)
395-
}
396-
397349
pub fn variable_nomod(input: Span) -> PResult<Value> {
398350
let (rest, name) = preceded(char('$'), identifier)(input)?;
399351
let pos = input.up_to(&rest).to_owned();
@@ -584,12 +536,12 @@ mod test {
584536

585537
#[test]
586538
fn simple_number() {
587-
check_expr("4;", number(4.))
539+
check_expr("4;", Value::scalar(4.))
588540
}
589541

590542
#[test]
591543
fn simple_number_neg() {
592-
check_expr("-4;", number(-4.))
544+
check_expr("-4;", Value::scalar(-4.))
593545
}
594546

595547
#[test]
@@ -599,23 +551,19 @@ mod test {
599551

600552
#[test]
601553
fn simple_number_dec() {
602-
check_expr("4.34;", number(4.34))
554+
check_expr("4.34;", Value::scalar(4.34))
603555
}
604556
#[test]
605557
fn simple_number_onlydec() {
606-
check_expr(".34;", number(0.34))
558+
check_expr(".34;", Value::scalar(0.34))
607559
}
608560
#[test]
609561
fn simple_number_onlydec_neg() {
610-
check_expr("-.34;", number(-0.34))
562+
check_expr("-.34;", Value::scalar(-0.34))
611563
}
612564
#[test]
613565
fn simple_number_onlydec_pos() {
614-
check_expr("+.34;", number(0.34))
615-
}
616-
617-
fn number(value: f64) -> Value {
618-
Value::scalar(value)
566+
check_expr("+.34;", Value::scalar(0.34))
619567
}
620568

621569
#[test]

rsass/src/value/number.rs

+27-23
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,27 @@ use std::ops::{Add, Div, Mul, Neg, Rem, Sub};
66
///
77
/// Only the actual numeric value is included, not any unit.
88
/// Internally, a number is represented as a floating-point value.
9-
#[derive(Clone, PartialEq, PartialOrd)]
9+
#[derive(Clone)]
1010
pub struct Number {
1111
value: f64,
1212
}
13+
impl PartialEq for Number {
14+
fn eq(&self, other: &Self) -> bool {
15+
(self.value - other.value).abs() / self.value.abs() <= f64::EPSILON
16+
}
17+
}
1318
impl Eq for Number {}
1419

20+
impl PartialOrd for Number {
21+
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
22+
if self == other {
23+
Some(std::cmp::Ordering::Equal)
24+
} else {
25+
self.value.partial_cmp(&other.value)
26+
}
27+
}
28+
}
29+
1530
impl Neg for Number {
1631
type Output = Self;
1732
fn neg(self) -> Self {
@@ -88,28 +103,17 @@ impl Number {
88103
self.value.is_finite()
89104
}
90105

91-
/// Returns true if the number is an integer.
106+
/// Convert this number to an `i64` if it is (very close to)
107+
/// integer and in range for `i64`, otherwise return `Err(self)`.
92108
pub fn into_integer(self) -> Result<i64, Self> {
93-
let sr = self.value.round();
94-
if (sr - self.value).abs() <= f32::EPSILON.into() {
95-
Ok(sr as i64)
109+
let int = self.value.round() as i64;
110+
if ((int as f64) - self.value).abs() <= f32::EPSILON.into() {
111+
Ok(int)
96112
} else {
97113
Err(self)
98114
}
99115
}
100116

101-
/// Converts to an integer, rounding towards zero.
102-
///
103-
/// An integer that is too big to fit in an i64 returns `None`.
104-
pub fn to_integer(&self) -> Option<i64> {
105-
let i = self.value.ceil() as i64;
106-
let ia = i.abs() as f64;
107-
if ia <= self.value.abs() && ia + 1. >= self.value.abs() {
108-
Some(i)
109-
} else {
110-
None
111-
}
112-
}
113117
/// Computes self^p.
114118
pub fn powi(self, p: i32) -> Self {
115119
self.value.powi(p).into()
@@ -131,7 +135,7 @@ impl From<i64> for Number {
131135
}
132136
impl From<i32> for Number {
133137
fn from(value: i32) -> Self {
134-
Self::from(i64::from(value))
138+
Self::from(f64::from(value))
135139
}
136140
}
137141
impl From<usize> for Number {
@@ -305,30 +309,30 @@ impl<'a> fmt::Display for Formatted<'a, Number> {
305309

306310
impl fmt::Debug for Number {
307311
fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
308-
write!(out, "Number {}", self.value)
312+
write!(out, "Number({:?})", self.value)
309313
}
310314
}
311315

312316
#[test]
313317
fn debug_integer() {
314-
assert_eq!(format!("{:?}", Number::from(17)), "Number 17",);
318+
assert_eq!(format!("{:?}", Number::from(17)), "Number(17.0)",);
315319
}
316320
#[test]
317321
fn debug_long_integer() {
318-
assert_eq!(format!("{:#?}", Number::from(17)), "Number 17",);
322+
assert_eq!(format!("{:#?}", Number::from(17)), "Number(17.0)",);
319323
}
320324

321325
#[test]
322326
fn debug_float() {
323-
assert_eq!(format!("{:?}", Number::from(17.5)), "Number 17.5",);
327+
assert_eq!(format!("{:?}", Number::from(17.5)), "Number(17.5)",);
324328
}
325329

326330
#[test]
327331
fn debug_int_value() {
328332
assert_eq!(
329333
format!("{:#?}", crate::sass::Value::scalar(17)),
330334
"Numeric(\
331-
\n Number 17; UnitSet [],\
335+
\n Number(17.0); UnitSet [],\
332336
\n)",
333337
);
334338
}

rsass/src/value/numeric.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::ops::{Div, Mul, Neg};
55

66
/// A Numeric value is a [`Number`] with a [`Unit`] (which may be
77
/// `Unit::None`).
8-
#[derive(Clone, Eq)]
8+
#[derive(Clone)]
99
pub struct Numeric {
1010
/// The number value of this numeric.
1111
pub value: Number,
@@ -55,7 +55,7 @@ impl Numeric {
5555
pub fn as_unit(&self, unit: Unit) -> Option<Number> {
5656
self.unit
5757
.scale_to_unit(&unit)
58-
.map(|scale| &self.value * &scale)
58+
.map(|scale| &self.value * &Number::from(scale))
5959
}
6060
/// Convert this numeric value to a given unit, if possible.
6161
///
@@ -67,7 +67,9 @@ impl Numeric {
6767
/// assert_eq!(inch.as_unit(Unit::Deg), None);
6868
/// ```
6969
pub fn as_unitset(&self, unit: &UnitSet) -> Option<Number> {
70-
self.unit.scale_to(unit).map(|scale| &self.value * &scale)
70+
self.unit
71+
.scale_to(unit)
72+
.map(|scale| &self.value * &Number::from(scale))
7173
}
7274

7375
/// Convert this numeric value to a given unit, if possible.
@@ -101,6 +103,7 @@ impl PartialEq for Numeric {
101103
self.partial_cmp(other) == Some(std::cmp::Ordering::Equal)
102104
}
103105
}
106+
impl Eq for Numeric {}
104107

105108
impl PartialOrd for Numeric {
106109
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {

rsass/src/value/unit.rs

+8-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
//! The Unit enum defines css units
22
3-
use crate::value::Number;
43
use std::f64::consts::FRAC_1_PI;
54
use std::fmt;
65

@@ -150,9 +149,9 @@ impl Unit {
150149
/// Get a scaling factor to convert this unit to another unit.
151150
///
152151
/// Returns None if the units are of different dimension.
153-
pub fn scale_to(&self, other: &Self) -> Option<Number> {
152+
pub fn scale_to(&self, other: &Self) -> Option<f64> {
154153
if self == other {
155-
Some(1.into())
154+
Some(1.)
156155
} else if self.dimension() == other.dimension() {
157156
Some(self.scale_factor() / other.scale_factor())
158157
} else {
@@ -163,12 +162,12 @@ impl Unit {
163162
/// Some of these are exact and correct, others are more arbitrary.
164163
/// When comparing 10cm to 4in, these factors will give correct results.
165164
/// When comparing rems to vw, who can say?
166-
pub(crate) fn scale_factor(&self) -> Number {
165+
pub(crate) fn scale_factor(&self) -> f64 {
167166
#[allow(clippy::match_same_arms)]
168-
Number::from(match *self {
169-
Self::Em | Self::Rem => 10. / 2.,
170-
Self::Ex => 10. / 3.,
171-
Self::Ch => 10. / 4.,
167+
match *self {
168+
Self::Em | Self::Rem => 5.,
169+
Self::Ex => 3.,
170+
Self::Ch => 2.,
172171
Self::Vw | Self::Vh | Self::Vmin | Self::Vmax => 1.,
173172
Self::Cm => 10.,
174173
Self::Mm => 1.,
@@ -198,7 +197,7 @@ impl Unit {
198197
Self::None => 1.,
199198

200199
Self::Unknown(_) => 1.,
201-
})
200+
}
202201
}
203202
}
204203

0 commit comments

Comments
 (0)