Skip to content
This repository was archived by the owner on May 28, 2024. It is now read-only.

Commit a87416f

Browse files
committed
Replace the FromCowStr trait with From<String> + From<&str>
1 parent 88f555d commit a87416f

File tree

1 file changed

+34
-31
lines changed

1 file changed

+34
-31
lines changed

src/parser.rs

+34-31
Original file line numberDiff line numberDiff line change
@@ -14,36 +14,36 @@ use std::sync::Arc;
1414

1515
use HashMap;
1616

17-
/// Although it could, String does not implement From<Cow<str>>
18-
pub trait FromCowStr {
19-
fn from_cow_str(s: Cow<str>) -> Self;
20-
}
21-
22-
impl FromCowStr for String {
23-
fn from_cow_str(s: Cow<str>) -> Self {
24-
s.into_owned()
25-
}
26-
}
17+
macro_rules! with_bounds {
18+
( [ $( $CommonBounds: tt )* ] [ $( $FromStr: tt )* ]) => {
19+
fn from_cow_str<T>(cow: Cow<str>) -> T where T: $($FromStr)* {
20+
match cow {
21+
Cow::Borrowed(s) => T::from(s),
22+
Cow::Owned(s) => T::from(s),
23+
}
24+
}
2725

28-
impl FromCowStr for ::string_cache::Atom {
29-
fn from_cow_str(s: Cow<str>) -> Self {
30-
s.into()
31-
}
32-
}
26+
fn from_ascii_lowercase<T>(s: &str) -> T where T: $($FromStr)* {
27+
if let Some(first_uppercase) = s.bytes().position(|byte| byte >= b'A' && byte <= b'Z') {
28+
let mut string = s.to_owned();
29+
string[first_uppercase..].make_ascii_lowercase();
30+
T::from(string)
31+
} else {
32+
T::from(s)
33+
}
34+
}
3335

34-
macro_rules! with_bounds {
35-
($( $CommonBounds: tt )*) => {
3636
/// This trait allows to define the parser implementation in regards
3737
/// of pseudo-classes/elements
3838
pub trait SelectorImpl: Sized + Debug {
39-
type AttrValue: $($CommonBounds)* + Display + FromCowStr;
40-
type Identifier: $($CommonBounds)* + Display + FromCowStr + BloomHash;
41-
type ClassName: $($CommonBounds)* + Display + FromCowStr + BloomHash;
42-
type LocalName: $($CommonBounds)* + Display + FromCowStr + BloomHash
39+
type AttrValue: $($CommonBounds)* + $($FromStr)* + Display;
40+
type Identifier: $($CommonBounds)* + $($FromStr)* + Display + BloomHash;
41+
type ClassName: $($CommonBounds)* + $($FromStr)* + Display + BloomHash;
42+
type LocalName: $($CommonBounds)* + $($FromStr)* + Display + BloomHash
4343
+ Borrow<Self::BorrowedLocalName>;
4444
type NamespaceUrl: $($CommonBounds)* + Display + Default + BloomHash
4545
+ Borrow<Self::BorrowedNamespaceUrl>;
46-
type NamespacePrefix: $($CommonBounds)* + Display + Default + FromCowStr;
46+
type NamespacePrefix: $($CommonBounds)* + $($FromStr)* + Display + Default;
4747
type BorrowedNamespaceUrl: ?Sized + Eq;
4848
type BorrowedLocalName: ?Sized + Eq + Hash;
4949

@@ -88,7 +88,10 @@ macro_rules! with_bounds {
8888

8989
macro_rules! with_heap_size_bound {
9090
($( $HeapSizeOf: tt )*) => {
91-
with_bounds!(Clone + Eq + Hash $($HeapSizeOf)*);
91+
with_bounds! {
92+
[Clone + Eq + Hash $($HeapSizeOf)*]
93+
[From<String> + for<'a> From<&'a str>]
94+
}
9295
}
9396
}
9497

@@ -722,8 +725,8 @@ fn parse_type_selector<Impl: SelectorImpl>(context: &ParserContext<Impl>, input:
722725
match local_name {
723726
Some(name) => {
724727
compound_selector.push(SimpleSelector::LocalName(LocalName {
725-
lower_name: Impl::LocalName::from_cow_str(name.to_ascii_lowercase().into()),
726-
name: Impl::LocalName::from_cow_str(name),
728+
lower_name: from_ascii_lowercase(&name),
729+
name: from_cow_str(name),
727730
}))
728731
}
729732
None => (),
@@ -777,7 +780,7 @@ fn parse_qualified_name<'i, 't, Impl: SelectorImpl>
777780
let position = input.position();
778781
match input.next_including_whitespace() {
779782
Ok(Token::Delim('|')) => {
780-
let prefix = Impl::NamespacePrefix::from_cow_str(value);
783+
let prefix = from_cow_str(value);
781784
let result = context.namespace_prefixes.get(&prefix);
782785
let url = try!(result.ok_or(()));
783786
explicit_namespace(input, NamespaceConstraint::Specific(Namespace {
@@ -827,13 +830,13 @@ fn parse_attribute_selector<Impl: SelectorImpl>(context: &ParserContext<Impl>, i
827830
Some((_, None)) => unreachable!(),
828831
Some((namespace, Some(local_name))) => AttrSelector {
829832
namespace: namespace,
830-
lower_name: Impl::LocalName::from_cow_str(local_name.to_ascii_lowercase().into()),
831-
name: Impl::LocalName::from_cow_str(local_name),
833+
lower_name: from_ascii_lowercase(&local_name),
834+
name: from_cow_str(local_name),
832835
},
833836
};
834837

835838
fn parse_value<Impl: SelectorImpl>(input: &mut Parser) -> Result<Impl::AttrValue, ()> {
836-
Ok(Impl::AttrValue::from_cow_str(try!(input.expect_ident_or_string())))
839+
Ok(from_cow_str(try!(input.expect_ident_or_string())))
837840
}
838841
// TODO: deal with empty value or value containing whitespace (see spec)
839842
match input.next() {
@@ -991,13 +994,13 @@ fn parse_one_simple_selector<Impl: SelectorImpl>(context: &ParserContext<Impl>,
991994
let start_position = input.position();
992995
match input.next_including_whitespace() {
993996
Ok(Token::IDHash(id)) => {
994-
let id = SimpleSelector::ID(Impl::Identifier::from_cow_str(id));
997+
let id = SimpleSelector::ID(from_cow_str(id));
995998
Ok(Some(SimpleSelectorParseResult::SimpleSelector(id)))
996999
}
9971000
Ok(Token::Delim('.')) => {
9981001
match input.next_including_whitespace() {
9991002
Ok(Token::Ident(class)) => {
1000-
let class = SimpleSelector::Class(Impl::ClassName::from_cow_str(class));
1003+
let class = SimpleSelector::Class(from_cow_str(class));
10011004
Ok(Some(SimpleSelectorParseResult::SimpleSelector(class)))
10021005
}
10031006
_ => Err(()),

0 commit comments

Comments
 (0)