use std::collections::HashMap;
use super::types::{ComputedStyle, StyleId};
#[derive(Clone)]
pub struct StylePool {
styles: Vec<ComputedStyle>,
intern_map: HashMap<ComputedStyle, StyleId>,
}
impl Default for StylePool {
fn default() -> Self {
Self::new()
}
}
impl StylePool {
pub fn new() -> Self {
let default_style = ComputedStyle::default();
let mut intern_map = HashMap::new();
intern_map.insert(default_style.clone(), StyleId::DEFAULT);
Self {
styles: vec![default_style],
intern_map,
}
}
pub fn intern(&mut self, style: ComputedStyle) -> StyleId {
if let Some(&id) = self.intern_map.get(&style) {
return id;
}
let id = StyleId(self.styles.len() as u32);
self.intern_map.insert(style.clone(), id);
self.styles.push(style);
id
}
pub fn get(&self, id: StyleId) -> Option<&ComputedStyle> {
self.styles.get(id.0 as usize)
}
pub fn len(&self) -> usize {
self.styles.len()
}
pub fn is_empty(&self) -> bool {
self.styles.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = (StyleId, &ComputedStyle)> {
self.styles
.iter()
.enumerate()
.map(|(i, s)| (StyleId(i as u32), s))
}
}
impl std::fmt::Debug for StylePool {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("StylePool")
.field("count", &self.styles.len())
.finish()
}
}
#[cfg(test)]
#[allow(clippy::field_reassign_with_default)]
mod tests {
use super::*;
use crate::style::FontWeight;
#[test]
fn test_style_pool_interning() {
let mut pool = StylePool::new();
let mut style1 = ComputedStyle::default();
style1.font_weight = FontWeight::BOLD;
let id1 = pool.intern(style1.clone());
let id2 = pool.intern(style1);
assert_eq!(id1, id2);
assert_eq!(pool.len(), 2); }
#[test]
fn test_style_pool_iter() {
let mut pool = StylePool::new();
let mut style = ComputedStyle::default();
style.font_weight = FontWeight::BOLD;
pool.intern(style);
let ids: Vec<StyleId> = pool.iter().map(|(id, _)| id).collect();
assert_eq!(ids, vec![StyleId(0), StyleId(1)]);
}
}