From 97344b150dc3532a881f3476d398c38c8305b8ae Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 6 Oct 2016 18:39:03 +0200 Subject: [PATCH] cow_to_ascii_lowercase() --- Cargo.lock | 1 + components/style/str.rs | 12 ++++++++++++ tests/unit/style/Cargo.toml | 1 + tests/unit/style/lib.rs | 1 + tests/unit/style/str.rs | 13 ++++++++++++- 5 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 679a7b7fe2d..d7e98579172 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2636,6 +2636,7 @@ dependencies = [ "cssparser 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "html5ever-atoms 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "owning_ref 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/components/style/str.rs b/components/style/str.rs index 73518625b6e..be763892118 100644 --- a/components/style/str.rs +++ b/components/style/str.rs @@ -3,6 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use num_traits::ToPrimitive; +use std::ascii::AsciiExt; +use std::borrow::Cow; use std::convert::AsRef; use std::iter::{Filter, Peekable}; use std::str::Split; @@ -125,3 +127,13 @@ pub fn str_join(strs: I, join: &str) -> String acc }) } + +/// Like AsciiExt::to_ascii_lowercase, but avoids allocating when the input is already lower-case. +pub fn cow_into_ascii_lowercase<'a, S: Into>>(s: S) -> Cow<'a, str> { + let mut cow = s.into(); + match cow.bytes().position(|byte| byte >= b'A' && byte <= b'Z') { + Some(first_uppercase) => cow.to_mut()[first_uppercase..].make_ascii_lowercase(), + None => {} + } + cow +} diff --git a/tests/unit/style/Cargo.toml b/tests/unit/style/Cargo.toml index c2a668caa4c..a7fe7971cf7 100644 --- a/tests/unit/style/Cargo.toml +++ b/tests/unit/style/Cargo.toml @@ -16,6 +16,7 @@ testing = ["style/testing"] app_units = "0.3" cssparser = {version = "0.7", features = ["heap_size"]} euclid = "0.10.1" +matches = "0.1" owning_ref = "0.2.2" parking_lot = "0.3" rustc-serialize = "0.3" diff --git a/tests/unit/style/lib.rs b/tests/unit/style/lib.rs index 1ca7414bf68..95cd087ccbf 100644 --- a/tests/unit/style/lib.rs +++ b/tests/unit/style/lib.rs @@ -10,6 +10,7 @@ extern crate app_units; extern crate cssparser; extern crate euclid; #[macro_use] extern crate html5ever_atoms; +#[macro_use] #[allow(unused_extern_crates)] extern crate matches; extern crate owning_ref; extern crate parking_lot; extern crate rustc_serialize; diff --git a/tests/unit/style/str.rs b/tests/unit/style/str.rs index dafbd8fb7da..45d747d4da8 100644 --- a/tests/unit/style/str.rs +++ b/tests/unit/style/str.rs @@ -2,7 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use style::str::{split_html_space_chars, str_join}; +use std::borrow::Cow; +use style::str::{split_html_space_chars, str_join, cow_into_ascii_lowercase}; #[test] pub fn split_html_space_chars_whitespace() { @@ -33,3 +34,13 @@ pub fn test_str_join_many() { let expected = "-alpha--beta-gamma-"; assert_eq!(actual, expected); } + +#[test] +pub fn test_cow_into_ascii_lowercase() { + assert!(matches!(cow_into_ascii_lowercase("abc.d"), Cow::Borrowed("abc.d"))); + let string = String::from("abc.d"); + assert!(matches!(cow_into_ascii_lowercase(string), Cow::Owned(ref s) if s == "abc.d")); + assert!(matches!(cow_into_ascii_lowercase("Abc.d"), Cow::Owned(ref s) if s == "abc.d")); + assert!(matches!(cow_into_ascii_lowercase("aBC.D"), Cow::Owned(ref s) if s == "abc.d")); + assert!(matches!(cow_into_ascii_lowercase("abc.D"), Cow::Owned(ref s) if s == "abc.d")); +}