optimize ExtendedSelector::into_selector
when there is only one reference to an `ExtendedSelector`, the selector will no longer do unnecessary cloning. this is a significant improvement as previously we were cloning *every* selector multiple times. note that this is optimization only occurs when the selector is being emitted.
This commit is contained in:
parent
ca861d488b
commit
52ecd1e2d0
164
src/lib.rs
164
src/lib.rs
@ -136,34 +136,33 @@ pub fn from_path(p: &str) -> Result<String> {
|
|||||||
let mut map = CodeMap::new();
|
let mut map = CodeMap::new();
|
||||||
let file = map.add_file(p.into(), String::from_utf8(fs::read(p)?)?);
|
let file = map.add_file(p.into(), String::from_utf8(fs::read(p)?)?);
|
||||||
let empty_span = file.span.subspan(0, 0);
|
let empty_span = file.span.subspan(0, 0);
|
||||||
let mut extender = Extender::new(empty_span);
|
|
||||||
Css::from_stmts(
|
let stmts = Parser {
|
||||||
Parser {
|
toks: &mut Lexer::new(&file)
|
||||||
toks: &mut Lexer::new(&file)
|
.collect::<Vec<Token>>()
|
||||||
.collect::<Vec<Token>>()
|
.into_iter()
|
||||||
.into_iter()
|
.peekmore(),
|
||||||
.peekmore(),
|
map: &mut map,
|
||||||
map: &mut map,
|
path: p.as_ref(),
|
||||||
path: p.as_ref(),
|
scopes: &mut NeverEmptyVec::new(Scope::new()),
|
||||||
scopes: &mut NeverEmptyVec::new(Scope::new()),
|
global_scope: &mut Scope::new(),
|
||||||
global_scope: &mut Scope::new(),
|
super_selectors: &mut NeverEmptyVec::new(Selector::new(empty_span)),
|
||||||
super_selectors: &mut NeverEmptyVec::new(Selector::new(empty_span)),
|
span_before: empty_span,
|
||||||
span_before: empty_span,
|
content: &mut Vec::new(),
|
||||||
content: &mut Vec::new(),
|
in_mixin: false,
|
||||||
in_mixin: false,
|
in_function: false,
|
||||||
in_function: false,
|
in_control_flow: false,
|
||||||
in_control_flow: false,
|
at_root: true,
|
||||||
at_root: true,
|
at_root_has_selector: false,
|
||||||
at_root_has_selector: false,
|
extender: &mut Extender::new(empty_span),
|
||||||
extender: &mut extender,
|
}
|
||||||
}
|
.parse()
|
||||||
.parse()
|
.map_err(|e| raw_to_parse_error(&map, *e))?;
|
||||||
.map_err(|e| raw_to_parse_error(&map, *e))?,
|
|
||||||
&mut extender,
|
Css::from_stmts(stmts)
|
||||||
)
|
.map_err(|e| raw_to_parse_error(&map, *e))?
|
||||||
.map_err(|e| raw_to_parse_error(&map, *e))?
|
.pretty_print(&map)
|
||||||
.pretty_print(&map, &mut extender)
|
.map_err(|e| raw_to_parse_error(&map, *e))
|
||||||
.map_err(|e| raw_to_parse_error(&map, *e))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write CSS to `buf`, constructed from a string
|
/// Write CSS to `buf`, constructed from a string
|
||||||
@ -182,34 +181,32 @@ pub fn from_string(p: String) -> Result<String> {
|
|||||||
let mut map = CodeMap::new();
|
let mut map = CodeMap::new();
|
||||||
let file = map.add_file("stdin".into(), p);
|
let file = map.add_file("stdin".into(), p);
|
||||||
let empty_span = file.span.subspan(0, 0);
|
let empty_span = file.span.subspan(0, 0);
|
||||||
let mut extender = Extender::new(empty_span);
|
let stmts = Parser {
|
||||||
Css::from_stmts(
|
toks: &mut Lexer::new(&file)
|
||||||
Parser {
|
.collect::<Vec<Token>>()
|
||||||
toks: &mut Lexer::new(&file)
|
.into_iter()
|
||||||
.collect::<Vec<Token>>()
|
.peekmore(),
|
||||||
.into_iter()
|
map: &mut map,
|
||||||
.peekmore(),
|
path: Path::new(""),
|
||||||
map: &mut map,
|
scopes: &mut NeverEmptyVec::new(Scope::new()),
|
||||||
path: Path::new(""),
|
global_scope: &mut Scope::new(),
|
||||||
scopes: &mut NeverEmptyVec::new(Scope::new()),
|
super_selectors: &mut NeverEmptyVec::new(Selector::new(empty_span)),
|
||||||
global_scope: &mut Scope::new(),
|
span_before: empty_span,
|
||||||
super_selectors: &mut NeverEmptyVec::new(Selector::new(empty_span)),
|
content: &mut Vec::new(),
|
||||||
span_before: empty_span,
|
in_mixin: false,
|
||||||
content: &mut Vec::new(),
|
in_function: false,
|
||||||
in_mixin: false,
|
in_control_flow: false,
|
||||||
in_function: false,
|
at_root: true,
|
||||||
in_control_flow: false,
|
at_root_has_selector: false,
|
||||||
at_root: true,
|
extender: &mut Extender::new(empty_span),
|
||||||
at_root_has_selector: false,
|
}
|
||||||
extender: &mut extender,
|
.parse()
|
||||||
}
|
.map_err(|e| raw_to_parse_error(&map, *e))?;
|
||||||
.parse()
|
|
||||||
.map_err(|e| raw_to_parse_error(&map, *e))?,
|
Css::from_stmts(stmts)
|
||||||
&mut extender,
|
.map_err(|e| raw_to_parse_error(&map, *e))?
|
||||||
)
|
.pretty_print(&map)
|
||||||
.map_err(|e| raw_to_parse_error(&map, *e))?
|
.map_err(|e| raw_to_parse_error(&map, *e))
|
||||||
.pretty_print(&map, &mut extender)
|
|
||||||
.map_err(|e| raw_to_parse_error(&map, *e))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wasm")]
|
#[cfg(feature = "wasm")]
|
||||||
@ -218,32 +215,31 @@ pub fn from_string(p: String) -> std::result::Result<String, JsValue> {
|
|||||||
let mut map = CodeMap::new();
|
let mut map = CodeMap::new();
|
||||||
let file = map.add_file("stdin".into(), p);
|
let file = map.add_file("stdin".into(), p);
|
||||||
let empty_span = file.span.subspan(0, 0);
|
let empty_span = file.span.subspan(0, 0);
|
||||||
let mut extender = Extender::new(empty_span);
|
|
||||||
Ok(Css::from_stmts(
|
let stmts = Parser {
|
||||||
Parser {
|
toks: &mut Lexer::new(&file)
|
||||||
toks: &mut Lexer::new(&file)
|
.collect::<Vec<Token>>()
|
||||||
.collect::<Vec<Token>>()
|
.into_iter()
|
||||||
.into_iter()
|
.peekmore(),
|
||||||
.peekmore(),
|
map: &mut map,
|
||||||
map: &mut map,
|
path: Path::new(""),
|
||||||
path: Path::new(""),
|
scopes: &mut NeverEmptyVec::new(Scope::new()),
|
||||||
scopes: &mut NeverEmptyVec::new(Scope::new()),
|
global_scope: &mut Scope::new(),
|
||||||
global_scope: &mut Scope::new(),
|
super_selectors: &mut NeverEmptyVec::new(Selector::new(empty_span)),
|
||||||
super_selectors: &mut NeverEmptyVec::new(Selector::new(empty_span)),
|
span_before: empty_span,
|
||||||
span_before: empty_span,
|
content: &mut Vec::new(),
|
||||||
content: &mut Vec::new(),
|
in_mixin: false,
|
||||||
in_mixin: false,
|
in_function: false,
|
||||||
in_function: false,
|
in_control_flow: false,
|
||||||
in_control_flow: false,
|
at_root: true,
|
||||||
at_root: true,
|
at_root_has_selector: false,
|
||||||
at_root_has_selector: false,
|
extender: &mut Extender::new(empty_span),
|
||||||
extender: &mut extender,
|
}
|
||||||
}
|
.parse()
|
||||||
.parse()
|
.map_err(|e| raw_to_parse_error(&map, *e).to_string())?;
|
||||||
.map_err(|e| raw_to_parse_error(&map, *e).to_string())?,
|
|
||||||
&mut extender,
|
Ok(Css::from_stmts(stmts)
|
||||||
)
|
.map_err(|e| raw_to_parse_error(&map, *e).to_string())?
|
||||||
.map_err(|e| raw_to_parse_error(&map, *e).to_string())?
|
.pretty_print(&map)
|
||||||
.pretty_print(&map, &mut extender)
|
.map_err(|e| raw_to_parse_error(&map, *e).to_string())?)
|
||||||
.map_err(|e| raw_to_parse_error(&map, *e).to_string())?)
|
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ use crate::{
|
|||||||
atrule::{media::MediaRule, SupportsRule, UnknownAtRule},
|
atrule::{media::MediaRule, SupportsRule, UnknownAtRule},
|
||||||
error::SassResult,
|
error::SassResult,
|
||||||
parse::Stmt,
|
parse::Stmt,
|
||||||
selector::Extender,
|
|
||||||
selector::Selector,
|
selector::Selector,
|
||||||
style::Style,
|
style::Style,
|
||||||
};
|
};
|
||||||
@ -76,11 +75,11 @@ impl Css {
|
|||||||
Css { blocks: Vec::new() }
|
Css { blocks: Vec::new() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_stmts(s: Vec<Stmt>, extender: &mut Extender) -> SassResult<Self> {
|
pub(crate) fn from_stmts(s: Vec<Stmt>) -> SassResult<Self> {
|
||||||
Css::new().parse_stylesheet(s, extender)
|
Css::new().parse_stylesheet(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_stmt(&mut self, stmt: Stmt, extender: &mut Extender) -> SassResult<Vec<Toplevel>> {
|
fn parse_stmt(&mut self, stmt: Stmt) -> SassResult<Vec<Toplevel>> {
|
||||||
Ok(match stmt {
|
Ok(match stmt {
|
||||||
Stmt::RuleSet { selector, body } => {
|
Stmt::RuleSet { selector, body } => {
|
||||||
if body.is_empty() {
|
if body.is_empty() {
|
||||||
@ -93,7 +92,7 @@ impl Css {
|
|||||||
let mut vals = vec![Toplevel::new_rule(selector)];
|
let mut vals = vec![Toplevel::new_rule(selector)];
|
||||||
for rule in body {
|
for rule in body {
|
||||||
match rule {
|
match rule {
|
||||||
Stmt::RuleSet { .. } => vals.extend(self.parse_stmt(rule, extender)?),
|
Stmt::RuleSet { .. } => vals.extend(self.parse_stmt(rule)?),
|
||||||
Stmt::Style(s) => vals.get_mut(0).unwrap().push_style(s),
|
Stmt::Style(s) => vals.get_mut(0).unwrap().push_style(s),
|
||||||
Stmt::Comment(s) => vals.get_mut(0).unwrap().push_comment(s),
|
Stmt::Comment(s) => vals.get_mut(0).unwrap().push_comment(s),
|
||||||
Stmt::Media(m) => {
|
Stmt::Media(m) => {
|
||||||
@ -117,7 +116,7 @@ impl Css {
|
|||||||
Stmt::Return(..) => unreachable!(),
|
Stmt::Return(..) => unreachable!(),
|
||||||
Stmt::AtRoot { body } => {
|
Stmt::AtRoot { body } => {
|
||||||
body.into_iter().try_for_each(|r| -> SassResult<()> {
|
body.into_iter().try_for_each(|r| -> SassResult<()> {
|
||||||
vals.append(&mut self.parse_stmt(r, extender)?);
|
vals.append(&mut self.parse_stmt(r)?);
|
||||||
Ok(())
|
Ok(())
|
||||||
})?
|
})?
|
||||||
}
|
}
|
||||||
@ -150,10 +149,10 @@ impl Css {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_stylesheet(mut self, stmts: Vec<Stmt>, extender: &mut Extender) -> SassResult<Css> {
|
fn parse_stylesheet(mut self, stmts: Vec<Stmt>) -> SassResult<Css> {
|
||||||
let mut is_first = true;
|
let mut is_first = true;
|
||||||
for stmt in stmts {
|
for stmt in stmts {
|
||||||
let v = self.parse_stmt(stmt, extender)?;
|
let v = self.parse_stmt(stmt)?;
|
||||||
// this is how we print newlines between unrelated styles
|
// this is how we print newlines between unrelated styles
|
||||||
// it could probably be refactored
|
// it could probably be refactored
|
||||||
if !v.is_empty() {
|
if !v.is_empty() {
|
||||||
@ -169,9 +168,9 @@ impl Css {
|
|||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pretty_print(self, map: &CodeMap, extender: &mut Extender) -> SassResult<String> {
|
pub fn pretty_print(self, map: &CodeMap) -> SassResult<String> {
|
||||||
let mut string = Vec::new();
|
let mut string = Vec::new();
|
||||||
self._inner_pretty_print(&mut string, map, extender, 0)?;
|
self._inner_pretty_print(&mut string, map, 0)?;
|
||||||
if string.iter().any(|s| !s.is_ascii()) {
|
if string.iter().any(|s| !s.is_ascii()) {
|
||||||
return Ok(format!("@charset \"UTF-8\";\n{}", unsafe {
|
return Ok(format!("@charset \"UTF-8\";\n{}", unsafe {
|
||||||
String::from_utf8_unchecked(string)
|
String::from_utf8_unchecked(string)
|
||||||
@ -184,7 +183,6 @@ impl Css {
|
|||||||
self,
|
self,
|
||||||
buf: &mut Vec<u8>,
|
buf: &mut Vec<u8>,
|
||||||
map: &CodeMap,
|
map: &CodeMap,
|
||||||
extender: &mut Extender,
|
|
||||||
nesting: usize,
|
nesting: usize,
|
||||||
) -> SassResult<()> {
|
) -> SassResult<()> {
|
||||||
let mut has_written = false;
|
let mut has_written = false;
|
||||||
@ -231,12 +229,7 @@ impl Css {
|
|||||||
writeln!(buf, " {{")?;
|
writeln!(buf, " {{")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Css::from_stmts(body, extender)?._inner_pretty_print(
|
Css::from_stmts(body)?._inner_pretty_print(buf, map, nesting + 1)?;
|
||||||
buf,
|
|
||||||
map,
|
|
||||||
extender,
|
|
||||||
nesting + 1,
|
|
||||||
)?;
|
|
||||||
writeln!(buf, "{}}}", padding)?;
|
writeln!(buf, "{}}}", padding)?;
|
||||||
}
|
}
|
||||||
Toplevel::Supports { params, body } => {
|
Toplevel::Supports { params, body } => {
|
||||||
@ -258,12 +251,7 @@ impl Css {
|
|||||||
writeln!(buf, " {{")?;
|
writeln!(buf, " {{")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Css::from_stmts(body, extender)?._inner_pretty_print(
|
Css::from_stmts(body)?._inner_pretty_print(buf, map, nesting + 1)?;
|
||||||
buf,
|
|
||||||
map,
|
|
||||||
extender,
|
|
||||||
nesting + 1,
|
|
||||||
)?;
|
|
||||||
writeln!(buf, "{}}}", padding)?;
|
writeln!(buf, "{}}}", padding)?;
|
||||||
}
|
}
|
||||||
Toplevel::Media { query, body } => {
|
Toplevel::Media { query, body } => {
|
||||||
@ -275,12 +263,7 @@ impl Css {
|
|||||||
writeln!(buf)?;
|
writeln!(buf)?;
|
||||||
}
|
}
|
||||||
writeln!(buf, "{}@media {} {{", padding, query)?;
|
writeln!(buf, "{}@media {} {{", padding, query)?;
|
||||||
Css::from_stmts(body, extender)?._inner_pretty_print(
|
Css::from_stmts(body)?._inner_pretty_print(buf, map, nesting + 1)?;
|
||||||
buf,
|
|
||||||
map,
|
|
||||||
extender,
|
|
||||||
nesting + 1,
|
|
||||||
)?;
|
|
||||||
writeln!(buf, "{}}}", padding)?;
|
writeln!(buf, "{}}}", padding)?;
|
||||||
}
|
}
|
||||||
Toplevel::Style(s) => {
|
Toplevel::Style(s) => {
|
||||||
|
@ -37,7 +37,10 @@ impl ExtendedSelector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_selector(self) -> Selector {
|
pub fn into_selector(self) -> Selector {
|
||||||
Selector(self.0.borrow().clone())
|
Selector(match Rc::try_unwrap(self.0) {
|
||||||
|
Ok(v) => v.into_inner(),
|
||||||
|
Err(v) => v.borrow().clone(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_inner(&mut self, selector: SelectorList) {
|
pub fn set_inner(&mut self, selector: SelectorList) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user