use core::fmt;
use bun_alloc::Arena;
use bun_ast::ImportRecord;
use bun_collections::ArrayHashMap;
use crate as css;
use crate::css_rules::{CssRuleList, Location};
use crate::{PrintErr, Printer, SmallList};
#[derive(Default)]
pub struct LayerName {
pub v: SmallList<&'static [u8], 1>,
}
pub type LayerNameHashMap<V> = ArrayHashMap<LayerName, V>;
impl core::hash::Hash for LayerName {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
for part in self.v.slice() {
state.write(part);
}
}
}
impl PartialEq for LayerName {
fn eq(&self, other: &Self) -> bool {
self.eql(other)
}
}
impl Eq for LayerName {}
impl Clone for LayerName {
fn clone(&self) -> Self {
LayerName { v: self.v.clone() }
}
}
impl LayerName {
pub fn clone_with_import_records(&self, bump: &Arena, _: &mut Vec<ImportRecord>) -> Self {
LayerName {
v: SmallList::from_arena_iter(bump, self.v.slice().iter().copied()),
}
}
pub fn eql(&self, rhs: &LayerName) -> bool {
if self.v.len() != rhs.v.len() {
return false;
}
for (l, r) in self.v.slice().iter().zip(rhs.v.slice()) {
if **l != **r {
return false;
}
}
true
}
pub fn parse(input: &mut css::css_parser::Parser<'_>) -> css::css_parser::CssResult<LayerName> {
let mut parts: SmallList<&'static [u8], 1> = SmallList::default();
let ident = input.expect_ident_cloned()?;
parts.append(ident);
loop {
let try_parse_fn =
|i: &mut css::css_parser::Parser<'_>| -> css::css_parser::CssResult<&'static [u8]> {
let start_location = i.current_source_location();
let tok = i.next_including_whitespace()?.clone();
if !matches!(tok, css::Token::Delim(c) if c == u32::from(b'.')) {
return Err(start_location.new_basic_unexpected_token_error(tok));
}
let start_location = i.current_source_location();
let tok = i.next_including_whitespace()?.clone();
if let css::Token::Ident(ident) = tok {
return Ok(ident);
}
Err(start_location.new_basic_unexpected_token_error(tok))
};
match input.try_parse(try_parse_fn) {
Ok(name) => parts.append(name),
Err(_) => return Ok(LayerName { v: parts }),
}
}
}
pub fn to_css(&self, dest: &mut Printer) -> Result<(), PrintErr> {
dest.write_separated(
self.v.slice(),
|d| d.write_char(b'.'),
|d, name| d.serialize_identifier(name),
)
}
pub fn deep_clone(&self, _bump: &Arena) -> Self {
LayerName { v: self.v.clone() }
}
}
impl css::generics::ToCss for LayerName {
#[inline]
fn to_css(&self, dest: &mut Printer) -> Result<(), PrintErr> {
LayerName::to_css(self, dest)
}
}
impl fmt::Display for LayerName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut first = true;
for name in self.v.slice() {
if first {
first = false;
} else {
f.write_str(".")?;
}
fmt::Display::fmt(bstr::BStr::new(name), f)?;
}
Ok(())
}
}
pub struct LayerBlockRule<R> {
pub name: Option<LayerName>,
pub rules: CssRuleList<R>,
pub loc: Location,
}
impl<R> LayerBlockRule<R> {
pub fn deep_clone<'bump>(&self, bump: &'bump Arena) -> Self
where
R: css::generics::DeepClone<'bump>,
{
Self {
name: self.name.as_ref().map(|n| n.deep_clone(bump)),
rules: self.rules.deep_clone(bump),
loc: self.loc,
}
}
pub fn to_css(&self, dest: &mut Printer) -> Result<(), PrintErr> {
dest.write_str("@layer")?;
if let Some(name) = &self.name {
dest.write_char(b' ')?;
name.to_css(dest)?;
}
dest.block(|d| {
d.newline()?;
self.rules.to_css(d)
})
}
}
pub struct LayerStatementRule {
pub names: SmallList<LayerName, 1>,
pub loc: Location,
}
impl LayerStatementRule {
pub fn deep_clone(&self, bump: &Arena) -> Self {
let mut names = SmallList::<LayerName, 1>::default();
for n in self.names.slice() {
names.append(n.deep_clone(bump));
}
Self {
names,
loc: self.loc,
}
}
pub fn to_css(&self, dest: &mut Printer) -> Result<(), PrintErr> {
if self.names.len() > 0 {
dest.write_str("@layer ")?;
css::to_css::from_list(self.names.slice(), dest)?;
dest.write_char(b';')
} else {
dest.write_str("@layer;")
}
}
}