use crate::Renderer;
use std::borrow::Cow;
pub trait Attr {
fn write_attr(&self, name: &str, r: &mut dyn Renderer);
}
fn write_pair(name: &str, value: &dyn core::fmt::Display, r: &mut dyn Renderer) {
r.write_raw(" ");
r.write_raw(name);
r.write_raw("=\"");
r.write_escaped(value);
r.write_raw("\"");
}
impl Attr for bool {
fn write_attr(&self, name: &str, r: &mut dyn Renderer) {
if *self {
r.write_raw(" ");
r.write_raw(name);
}
}
}
impl<T: Attr> Attr for Option<T> {
fn write_attr(&self, name: &str, r: &mut dyn Renderer) {
if let Some(value) = self {
value.write_attr(name, r);
}
}
}
impl<T: Attr + ?Sized> Attr for &T {
fn write_attr(&self, name: &str, r: &mut dyn Renderer) {
(**self).write_attr(name, r);
}
}
impl Attr for str {
fn write_attr(&self, name: &str, r: &mut dyn Renderer) {
write_pair(name, &self, r);
}
}
impl Attr for String {
fn write_attr(&self, name: &str, r: &mut dyn Renderer) {
write_pair(name, &self.as_str(), r);
}
}
impl Attr for Cow<'_, str> {
fn write_attr(&self, name: &str, r: &mut dyn Renderer) {
write_pair(name, &self.as_ref(), r);
}
}
macro_rules! attr_via_display {
($($t:ty),* $(,)?) => {$(
impl Attr for $t {
fn write_attr(&self, name: &str, r: &mut dyn Renderer) {
write_pair(name, self, r);
}
}
)*};
}
attr_via_display!(
char, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64
);
pub trait AttrSpread {
fn write_attrs(&self, r: &mut dyn Renderer);
}
impl<T: AttrSpread + ?Sized> AttrSpread for &T {
fn write_attrs(&self, r: &mut dyn Renderer) {
(**self).write_attrs(r);
}
}
impl AttrSpread for &'static str {
fn write_attrs(&self, r: &mut dyn Renderer) {
if !self.is_empty() {
r.write_raw(" ");
r.write_raw(self);
}
}
}
impl<T: AttrSpread> AttrSpread for Option<T> {
fn write_attrs(&self, r: &mut dyn Renderer) {
if let Some(inner) = self {
inner.write_attrs(r);
}
}
}
impl<K: AsRef<str>, V: AsRef<str>> AttrSpread for [(K, V)] {
fn write_attrs(&self, r: &mut dyn Renderer) {
for (key, value) in self {
r.write_raw(" ");
r.write_escaped(&key.as_ref());
r.write_raw("=\"");
r.write_escaped(&value.as_ref());
r.write_raw("\"");
}
}
}
impl<K: AsRef<str>, V: AsRef<str>> AttrSpread for Vec<(K, V)> {
fn write_attrs(&self, r: &mut dyn Renderer) {
self.as_slice().write_attrs(r);
}
}
#[derive(Debug, Default, Clone)]
pub struct ClassList {
names: Vec<String>,
}
impl ClassList {
pub fn new() -> Self {
Self::default()
}
pub fn add(&mut self, text: &str) {
for name in text.split_whitespace() {
if !self.names.iter().any(|n| n == name) {
self.names.push(name.to_string());
}
}
}
pub fn set(&mut self, text: &str, on: bool) {
if on {
self.add(text);
} else {
for name in text.split_whitespace() {
self.names.retain(|n| n != name);
}
}
}
pub fn is_empty(&self) -> bool {
self.names.is_empty()
}
pub fn to_value(&self) -> String {
self.names.join(" ")
}
pub fn write_attr(&self, name: &str, r: &mut dyn Renderer) {
if !self.is_empty() {
write_pair(name, &self.to_value(), r);
}
}
}
pub trait ClassItem {
fn add_to(&self, list: &mut ClassList);
}
impl<T: ClassItem + ?Sized> ClassItem for &T {
fn add_to(&self, list: &mut ClassList) {
(**self).add_to(list);
}
}
impl<T: ClassItem> ClassItem for Option<T> {
fn add_to(&self, list: &mut ClassList) {
if let Some(item) = self {
item.add_to(list);
}
}
}
impl ClassItem for str {
fn add_to(&self, list: &mut ClassList) {
list.add(self);
}
}
impl ClassItem for String {
fn add_to(&self, list: &mut ClassList) {
list.add(self);
}
}
impl ClassItem for Cow<'_, str> {
fn add_to(&self, list: &mut ClassList) {
list.add(self.as_ref());
}
}