use std::fmt;
use super::attribute::{AnyAttribute, Attribute, is_attr};
use crate::style::{PropertyValue, StoredValue, StyleValueDyn};
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct AttrDirty(pub u64);
impl AttrDirty {
pub const NONE: Self = Self(0);
pub fn insert(&mut self, index: u8) {
self.0 |= 1 << index;
}
pub fn any(&self) -> bool {
self.0 != 0
}
pub fn union(self, other: Self) -> Self {
Self(self.0 | other.0)
}
}
pub(crate) struct Entry {
pub(crate) index: u8,
pub(crate) attr: &'static dyn AnyAttribute,
pub(crate) value: StoredValue,
}
impl Clone for Entry {
fn clone(&self) -> Self {
Self {
index: self.index,
attr: self.attr,
value: self.value.clone_value(),
}
}
}
#[derive(Default, Clone)]
pub struct Attrs {
entries: Vec<Entry>,
}
impl Attrs {
pub fn empty() -> &'static Attrs {
static EMPTY: Attrs = Attrs {
entries: Vec::new(),
};
&EMPTY
}
pub fn get<T: PropertyValue>(&self, attribute: &Attribute<T>) -> Option<&T> {
self.entries
.iter()
.find(|e| is_attr(e.attr, attribute))
.and_then(|e| e.value.as_any().downcast_ref::<T>())
}
pub fn contains<T: 'static>(&self, attribute: &Attribute<T>) -> bool {
self.entries.iter().any(|e| is_attr(e.attr, attribute))
}
pub fn get_by_name(&self, name: &str) -> Option<&dyn StyleValueDyn> {
self.entries
.iter()
.find(|e| e.attr.name() == name)
.map(|e| &*e.value)
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = (&'static dyn AnyAttribute, &dyn StyleValueDyn)> {
self.entries.iter().map(|e| (e.attr, &*e.value))
}
pub fn keys(&self) -> AttrDirty {
AttrDirty(self.entries.iter().fold(0, |m, e| m | 1 << e.index))
}
pub(crate) fn insert(&mut self, entry: Entry) {
match self.entries.binary_search_by_key(&entry.index, |e| e.index) {
Ok(i) => self.entries[i] = entry,
Err(i) => self.entries.insert(i, entry),
}
}
pub(crate) fn remove_index(&mut self, index: u8) -> bool {
match self.entries.binary_search_by_key(&index, |e| e.index) {
Ok(i) => {
self.entries.remove(i);
true
}
Err(_) => false,
}
}
pub(crate) fn take_events(&mut self) -> Attrs {
if !self.entries.iter().any(|e| e.attr.is_event()) {
return Attrs::default();
}
let (events, retained) = std::mem::take(&mut self.entries)
.into_iter()
.partition(|e| e.attr.is_event());
self.entries = retained;
Attrs { entries: events }
}
pub(crate) fn overlay_delta(&mut self, delta: &mut Attrs) -> AttrDirty {
let mut dirty = AttrDirty::NONE;
for entry in delta.entries.drain(..) {
match self.entries.binary_search_by_key(&entry.index, |e| e.index) {
Ok(i) => {
if !self.entries[i].value.dyn_eq(&*entry.value) {
dirty.insert(entry.index);
self.entries[i] = entry;
}
}
Err(i) => {
dirty.insert(entry.index);
self.entries.insert(i, entry);
}
}
}
dirty
}
}
impl fmt::Debug for Attrs {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_map()
.entries(self.entries.iter().map(|e| (e.attr.name(), &*e.value)))
.finish()
}
}
impl PartialEq for Attrs {
fn eq(&self, other: &Self) -> bool {
self.entries.len() == other.entries.len()
&& self
.entries
.iter()
.zip(&other.entries)
.all(|(a, b)| a.index == b.index && a.value.dyn_eq(&*b.value))
}
}