use super::{
maybe_next_attr_erasure_macros::next_attr_output_type, NextAttribute,
};
use crate::{
html::attribute::{
maybe_next_attr_erasure_macros::next_attr_combine, Attribute,
AttributeValue,
},
view::{add_attr::AddAnyAttr, Position, ToTemplate},
};
use std::{borrow::Cow, sync::Arc};
#[inline(always)]
pub fn custom_attribute<K, V>(key: K, value: V) -> CustomAttr<K, V>
where
K: CustomAttributeKey,
V: AttributeValue,
{
CustomAttr { key, value }
}
#[derive(Debug)]
pub struct CustomAttr<K, V>
where
K: CustomAttributeKey,
V: AttributeValue,
{
key: K,
value: V,
}
impl<K, V> Clone for CustomAttr<K, V>
where
K: CustomAttributeKey,
V: AttributeValue + Clone,
{
fn clone(&self) -> Self {
Self {
key: self.key.clone(),
value: self.value.clone(),
}
}
}
impl<K, V> Attribute for CustomAttr<K, V>
where
K: CustomAttributeKey,
V: AttributeValue,
{
const MIN_LENGTH: usize = 0;
type AsyncOutput = CustomAttr<K, V::AsyncOutput>;
type State = V::State;
type Cloneable = CustomAttr<K, V::Cloneable>;
type CloneableOwned = CustomAttr<K, V::CloneableOwned>;
fn html_len(&self) -> usize {
self.key.as_ref().len() + 3 + self.value.html_len()
}
fn to_html(
self,
buf: &mut String,
_class: &mut String,
_style: &mut String,
_inner_html: &mut String,
) {
self.value.to_html(self.key.as_ref(), buf);
}
fn hydrate<const FROM_SERVER: bool>(
self,
el: &crate::renderer::types::Element,
) -> Self::State {
if !K::KEY.is_empty() {
self.value.hydrate::<FROM_SERVER>(self.key.as_ref(), el)
} else {
self.value.build(el, self.key.as_ref())
}
}
fn build(self, el: &crate::renderer::types::Element) -> Self::State {
self.value.build(el, self.key.as_ref())
}
fn rebuild(self, state: &mut Self::State) {
self.value.rebuild(self.key.as_ref(), state);
}
fn into_cloneable(self) -> Self::Cloneable {
CustomAttr {
key: self.key,
value: self.value.into_cloneable(),
}
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
CustomAttr {
key: self.key,
value: self.value.into_cloneable_owned(),
}
}
fn dry_resolve(&mut self) {
self.value.dry_resolve();
}
async fn resolve(self) -> Self::AsyncOutput {
CustomAttr {
key: self.key,
value: self.value.resolve().await,
}
}
}
impl<K, V> NextAttribute for CustomAttr<K, V>
where
K: CustomAttributeKey,
V: AttributeValue,
{
next_attr_output_type!(Self, NewAttr);
fn add_any_attr<NewAttr: Attribute>(
self,
new_attr: NewAttr,
) -> Self::Output<NewAttr> {
next_attr_combine!(self, new_attr)
}
}
impl<K, V> ToTemplate for CustomAttr<K, V>
where
K: CustomAttributeKey,
V: AttributeValue,
{
fn to_template(
buf: &mut String,
_class: &mut String,
_style: &mut String,
_inner_html: &mut String,
_position: &mut Position,
) {
if !K::KEY.is_empty() {
V::to_template(K::KEY, buf);
}
}
}
pub trait CustomAttributeKey: Clone + AsRef<str> + Send + 'static {
const KEY: &'static str;
}
impl CustomAttributeKey for &'static str {
const KEY: &'static str = "";
}
impl CustomAttributeKey for Cow<'static, str> {
const KEY: &'static str = "";
}
impl CustomAttributeKey for String {
const KEY: &'static str = "";
}
impl CustomAttributeKey for Arc<str> {
const KEY: &'static str = "";
}
#[cfg(feature = "nightly")]
impl<const K: &'static str> CustomAttributeKey
for crate::view::static_types::Static<K>
{
const KEY: &'static str = K;
}
pub trait CustomAttribute<K, V>
where
K: CustomAttributeKey,
V: AttributeValue,
Self: Sized + AddAnyAttr,
{
fn attr(
self,
key: K,
value: V,
) -> <Self as AddAnyAttr>::Output<CustomAttr<K, V>> {
self.add_any_attr(custom_attribute(key, value))
}
}
impl<T, K, V> CustomAttribute<K, V> for T
where
T: AddAnyAttr,
K: CustomAttributeKey,
V: AttributeValue,
{
}