Skip to content

Commit a5123a6

Browse files
committed
Serialize number to no more than necessary precision
1 parent ff1ba7d commit a5123a6

File tree

5 files changed

+68
-21
lines changed

5 files changed

+68
-21
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ encoding_rs = "0.5"
2020

2121
[dependencies]
2222
cssparser-macros = {path = "./macros", version = "0.3"}
23+
dtoa-short = "0.1"
2324
heapsize = {version = ">= 0.3, < 0.5", optional = true}
2425
matches = "0.1"
2526
phf = "0.7"

src/css-parsing-tests/component_value_list.json

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,12 @@
247247
["number", "-0.67", -0.67, "number"]
248248
],
249249

250+
"12.3e30 -0.0123e30 9999e-13", [
251+
["number", "1.23e31", 1.23e31, "number"], " ",
252+
["number", "-1.23e28", -1.23e28, "number"], " ",
253+
["number", "9.999e-10", 9.999e-10, "number"]
254+
],
255+
250256
"3. /* Decimal point must have following digits */", [
251257
["number", "3", 3, "integer"], ".", " "
252258
],
@@ -264,12 +270,12 @@
264270
["percentage", "12", 12, "integer"], " ",
265271
["percentage", "+34", 34, "integer"], " ",
266272
["percentage", "-45", -45, "integer"], " ",
267-
["percentage", "0.66999996", 0.67, "number"], " ",
273+
["percentage", "0.67", 0.67, "number"], " ",
268274
["percentage", "+0.89", 0.89, "number"], " ",
269275
["percentage", "-0.01", -0.01, "number"], " ",
270276
["percentage", "2.3", 2.3000000000, "number"], " ",
271277
["percentage", "+45.0", 45.0, "number"], " ",
272-
["percentage", "-0.66999996", -0.67, "number"]
278+
["percentage", "-0.67", -0.67, "number"]
273279
],
274280

275281
"12e2% +34e+1% -45E-0% .68e+3% +.79e-1% -.01E2% 2.3E+1% +45.0e6% -0.67e0%", [
@@ -281,7 +287,7 @@
281287
["percentage", "-1.0", -1, "number"], " ",
282288
["percentage", "23.0", 23, "number"], " ",
283289
["percentage", "+45000000.0", 45000000, "number"], " ",
284-
["percentage", "-0.66999996", -0.67, "number"]
290+
["percentage", "-0.67", -0.67, "number"]
285291
],
286292

287293
"12\\% /* Percent sign can not be escaped */", [

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ fn parse_border_spacing(_context: &ParserContext, input: &mut Parser)
6868

6969
#![recursion_limit="200"] // For color::parse_color_keyword
7070

71+
extern crate dtoa_short;
7172
#[macro_use] extern crate cssparser_macros;
7273
#[macro_use] extern crate matches;
7374
#[macro_use] extern crate procedural_masquerade;

src/serializer.rs

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5+
use dtoa_short;
56
use std::ascii::AsciiExt;
7+
use std::borrow::Cow;
68
use std::fmt::{self, Write};
9+
use std::str;
710

811
use super::Token;
912

@@ -41,7 +44,6 @@ pub trait ToCss {
4144
}
4245
}
4346

44-
4547
#[inline]
4648
fn write_numeric<W>(value: f32, int_value: Option<i32>, has_sign: bool, dest: &mut W)
4749
-> fmt::Result where W: fmt::Write {
@@ -50,15 +52,20 @@ fn write_numeric<W>(value: f32, int_value: Option<i32>, has_sign: bool, dest: &m
5052
dest.write_str("+")?;
5153
}
5254

53-
if value == 0.0 && value.is_sign_negative() {
55+
let result = if value == 0.0 && value.is_sign_negative() {
5456
// Negative zero. Work around #20596.
55-
dest.write_str("-0")?
57+
Cow::Borrowed("-0")
5658
} else {
57-
write!(dest, "{}", value)?
58-
}
59+
let mut result = String::new();
60+
dtoa_short::write(&mut result, value)?;
61+
result.into()
62+
};
5963

64+
dest.write_str(&result)?;
6065
if int_value.is_none() && value.fract() == 0. {
61-
dest.write_str(".0")?;
66+
if !result.contains(|c| c == '.' || c == 'e') {
67+
dest.write_str(".0")?;
68+
}
6269
}
6370
Ok(())
6471
}
@@ -267,7 +274,7 @@ impl<'a, W> fmt::Write for CssStringWriter<'a, W> where W: fmt::Write {
267274
}
268275

269276

270-
macro_rules! impl_tocss_for_number {
277+
macro_rules! impl_tocss_for_int {
271278
($T: ty) => {
272279
impl<'a> ToCss for $T {
273280
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
@@ -277,17 +284,27 @@ macro_rules! impl_tocss_for_number {
277284
}
278285
}
279286

280-
impl_tocss_for_number!(f32);
281-
impl_tocss_for_number!(f64);
282-
impl_tocss_for_number!(i8);
283-
impl_tocss_for_number!(u8);
284-
impl_tocss_for_number!(i16);
285-
impl_tocss_for_number!(u16);
286-
impl_tocss_for_number!(i32);
287-
impl_tocss_for_number!(u32);
288-
impl_tocss_for_number!(i64);
289-
impl_tocss_for_number!(u64);
287+
impl_tocss_for_int!(i8);
288+
impl_tocss_for_int!(u8);
289+
impl_tocss_for_int!(i16);
290+
impl_tocss_for_int!(u16);
291+
impl_tocss_for_int!(i32);
292+
impl_tocss_for_int!(u32);
293+
impl_tocss_for_int!(i64);
294+
impl_tocss_for_int!(u64);
295+
296+
macro_rules! impl_tocss_for_float {
297+
($T: ty) => {
298+
impl<'a> ToCss for $T {
299+
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
300+
dtoa_short::write(dest, *self)
301+
}
302+
}
303+
}
304+
}
290305

306+
impl_tocss_for_float!(f32);
307+
impl_tocss_for_float!(f64);
291308

292309
/// A category of token. See the `needs_separator_when_before` method.
293310
#[derive(Copy, Clone, Eq, PartialEq, Debug)]

src/tests.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ fn almost_equals(a: &Json, b: &Json) -> bool {
3131
(_, &Json::I64(b)) => almost_equals(a, &Json::F64(b as f64)),
3232
(_, &Json::U64(b)) => almost_equals(a, &Json::F64(b as f64)),
3333

34-
(&Json::F64(a), &Json::F64(b)) => (a - b).abs() < 1e-6,
34+
(&Json::F64(a), &Json::F64(b)) => (a - b).abs() <= a.abs() * 1e-6,
3535

3636
(&Json::Boolean(a), &Json::Boolean(b)) => a == b,
3737
(&Json::String(ref a), &Json::String(ref b)) => a == b,
@@ -1004,3 +1004,25 @@ fn parse_comments() {
10041004
assert_eq!(parser.current_source_map_url(), test.1);
10051005
}
10061006
}
1007+
1008+
#[test]
1009+
fn roundtrip_percentage_token() {
1010+
fn test_roundtrip(value: &str) {
1011+
let mut input = ParserInput::new(value);
1012+
let mut parser = Parser::new(&mut input);
1013+
let token = parser.next().unwrap();
1014+
assert_eq!(token.to_css_string(), value);
1015+
}
1016+
// Test simple number serialization
1017+
for i in 0..101 {
1018+
test_roundtrip(&format!("{}%", i));
1019+
for j in 0..10 {
1020+
if j != 0 {
1021+
test_roundtrip(&format!("{}.{}%", i, j));
1022+
}
1023+
for k in 1..10 {
1024+
test_roundtrip(&format!("{}.{}{}%", i, j, k));
1025+
}
1026+
}
1027+
}
1028+
}

0 commit comments

Comments
 (0)