use crate::custom_properties::{Name, SubstitutionFunctionKind};
use crate::properties_and_values::value::ComputedValue as ComputedRegisteredValue;
use crate::selector_map::PrecomputedHasher;
use indexmap::{Equivalent, IndexMap};
use rustc_hash::FxBuildHasher;
use servo_arc::Arc;
use std::hash::{BuildHasherDefault, Hash};
use std::sync::LazyLock;
#[derive(Clone, Debug, PartialEq)]
pub struct CustomPropertiesMap(Arc<Inner>);
impl Default for CustomPropertiesMap {
fn default() -> Self {
Self(EMPTY.clone())
}
}
pub type OwnMap =
IndexMap<Name, Option<ComputedRegisteredValue>, BuildHasherDefault<PrecomputedHasher>>;
static EMPTY: LazyLock<Arc<Inner>> = LazyLock::new(|| {
Arc::new_leaked(Inner {
own_properties: Default::default(),
parent: None,
len: 0,
ancestor_count: 0,
})
});
#[derive(Debug, Clone)]
struct Inner {
own_properties: OwnMap,
parent: Option<Arc<Inner>>,
len: usize,
ancestor_count: u8,
}
const ANCESTOR_COUNT_LIMIT: usize = 4;
pub struct Iter<'a> {
current: &'a Inner,
current_iter: indexmap::map::Iter<'a, Name, Option<ComputedRegisteredValue>>,
descendants: smallvec::SmallVec<[&'a Inner; ANCESTOR_COUNT_LIMIT]>,
}
impl<'a> Iterator for Iter<'a> {
type Item = (&'a Name, &'a Option<ComputedRegisteredValue>);
fn next(&mut self) -> Option<Self::Item> {
loop {
let (name, value) = match self.current_iter.next() {
Some(v) => v,
None => {
let parent = self.current.parent.as_deref()?;
self.descendants.push(self.current);
self.current = parent;
self.current_iter = parent.own_properties.iter();
continue;
},
};
for descendant in &self.descendants {
if descendant.own_properties.contains_key(name) {
continue;
}
}
return Some((name, value));
}
}
}
impl PartialEq for Inner {
fn eq(&self, other: &Self) -> bool {
if self.len != other.len {
return false;
}
if self.own_properties.as_slice() != other.own_properties.as_slice() {
return false;
}
self.parent == other.parent
}
}
impl Inner {
fn iter(&self) -> Iter<'_> {
Iter {
current: self,
current_iter: self.own_properties.iter(),
descendants: Default::default(),
}
}
fn is_empty(&self) -> bool {
self.len == 0
}
fn len(&self) -> usize {
self.len
}
fn get(&self, name: &Name) -> Option<&ComputedRegisteredValue> {
if let Some(p) = self.own_properties.get(name) {
return p.as_ref();
}
self.parent.as_ref()?.get(name)
}
fn insert(&mut self, name: &Name, value: Option<ComputedRegisteredValue>) {
let new = self.own_properties.insert(name.clone(), value).is_none();
if new && self.parent.as_ref().map_or(true, |p| p.get(name).is_none()) {
self.len += 1;
}
}
fn should_expand_chain(&self) -> bool {
const SMALL_THRESHOLD: usize = 8;
if self.own_properties.len() <= SMALL_THRESHOLD {
return false; }
self.ancestor_count < ANCESTOR_COUNT_LIMIT as u8
}
}
impl CustomPropertiesMap {
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn get_index(&self, index: usize) -> Option<(&Name, &Option<ComputedRegisteredValue>)> {
if index >= self.len() {
return None;
}
self.0.iter().nth(index)
}
pub fn get(&self, name: &Name) -> Option<&ComputedRegisteredValue> {
self.0.get(name)
}
fn do_insert(&mut self, name: &Name, value: Option<ComputedRegisteredValue>) {
if let Some(inner) = Arc::get_mut(&mut self.0) {
return inner.insert(name, value);
}
if self.get(name) == value.as_ref() {
return;
}
if !self.0.should_expand_chain() {
return Arc::make_mut(&mut self.0).insert(name, value);
}
let len = self.0.len;
let ancestor_count = self.0.ancestor_count + 1;
let mut new_inner = Inner {
own_properties: Default::default(),
parent: Some(self.0.clone()),
len,
ancestor_count,
};
new_inner.insert(name, value);
self.0 = Arc::new(new_inner);
}
pub fn insert(&mut self, name: &Name, value: ComputedRegisteredValue) {
self.do_insert(name, Some(value))
}
pub fn remove(&mut self, name: &Name) {
self.do_insert(name, None)
}
pub fn shrink_to_fit(&mut self) {
if let Some(inner) = Arc::get_mut(&mut self.0) {
inner.own_properties.shrink_to_fit()
}
}
pub fn iter(&self) -> Iter<'_> {
self.0.iter()
}
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct AllSubstitutionFunctions(IndexMap<Key, ComputedRegisteredValue, FxBuildHasher>);
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
struct Key(Name, SubstitutionFunctionKind);
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
struct KeyRef<'a>(&'a Name, SubstitutionFunctionKind);
impl<'a> Equivalent<Key> for KeyRef<'a> {
fn equivalent(&self, key: &Key) -> bool {
*self.0 == key.0 && self.1 == key.1
}
}
impl AllSubstitutionFunctions {
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[inline(always)]
pub fn get(
&self,
name: &Name,
kind: SubstitutionFunctionKind,
) -> Option<&ComputedRegisteredValue> {
debug_assert_ne!(kind, SubstitutionFunctionKind::Env);
self.0.get(&KeyRef(name, kind))
}
#[inline(always)]
pub fn insert(
&mut self,
name: &Name,
kind: SubstitutionFunctionKind,
value: ComputedRegisteredValue,
) {
debug_assert_ne!(kind, SubstitutionFunctionKind::Env);
let k = Key(name.clone(), kind);
self.0.insert(k, value);
}
#[inline(always)]
pub fn iter(
&self,
) -> impl Iterator<Item = (&Name, SubstitutionFunctionKind, &ComputedRegisteredValue)> {
self.0.iter().map(|(k, v)| (&k.0, k.1, v))
}
}