Skip to main content

ravel_web/attr/
mod.rs

1//! HTML attributes.
2
3use std::marker::PhantomData;
4
5use ravel::Builder;
6
7use crate::{BuildCx, RebuildCx, Web};
8
9use self::types::*;
10
11pub mod types;
12
13// TODO: Dedup with `Text`/`text`? It's the same thing for text nodes.
14/// A string type which is cloned to [`String`] to use as an attribute value.
15///
16/// This wrapepr type exists to draw attention to the fact that using a borrowed
17/// string value requires cloning to a persistent string in the attribute state.
18/// This also permits a more efficient implementation of `&'static str`, which
19/// does not need this wrapper.
20#[derive(Clone, Copy, PartialEq, Eq, Debug)]
21pub struct CloneString<V: AsRef<str>>(pub V);
22
23/// An arbitrary attribute.
24pub fn attr<Kind: AttrKind, Value: AttrValue>(
25    _: Kind,
26    value: Value,
27) -> Attr<Kind, Value> {
28    Attr {
29        value,
30        kind: PhantomData,
31    }
32}
33
34macro_rules! make_attr_value_type {
35    ($name:literal, $t:ident, $value_type:ty) => {
36        make_attr_value_type_state!(
37            $name,
38            $t,
39            $value_type,
40            std::convert::identity,
41            <V as AttrValue>::Saved
42        );
43    };
44    ($name:literal, $t:ident, $value_type:ty, $value_wrapper:ident) => {
45        make_attr_value_type_state!(
46            $name,
47            $t,
48            $value_type,
49            $value_wrapper,
50            <$value_wrapper as AttrValue>::Saved
51        );
52    };
53}
54
55macro_rules! make_attr_value_type_state {
56    ($name:literal, $t:ident, $value_type:ty, $value_wrapper:expr, $state_value:ty) => {
57        impl Builder<Web> for $t {
58            type State = AttrState<$state_value>;
59
60            fn build(self, cx: BuildCx) -> Self::State {
61                AttrState::build(
62                    cx.position.parent,
63                    $name,
64                    $value_wrapper(self.0),
65                )
66            }
67
68            fn rebuild(self, cx: RebuildCx, state: &mut Self::State) {
69                state.rebuild(cx.parent, $name, $value_wrapper(self.0))
70            }
71        }
72    };
73}
74
75macro_rules! make_attr_value_trait {
76    ($name:literal, $t:ident, $value_trait:ident) => {
77        make_attr_value_trait_state!(
78            $name,
79            $t,
80            $value_trait,
81            std::convert::identity,
82            <V as AttrValue>::Saved
83        );
84    };
85    ($name:literal, $t:ident, $value_trait:ident, $value_wrapper:ident) => {
86        make_attr_value_trait_state!(
87            $name,
88            $t,
89            $value_trait,
90            $value_wrapper,
91            <$value_wrapper<V> as AttrValue>::Saved
92        );
93    };
94}
95
96macro_rules! make_attr_value_trait_state {
97    ($name:literal, $t:ident, $value_trait:ident, $value_wrapper:expr, $state_value:ty) => {
98        impl<V: $value_trait> Builder<Web> for $t<V> {
99            type State = AttrState<$state_value>;
100
101            fn build(self, cx: BuildCx) -> Self::State {
102                AttrState::build(
103                    cx.position.parent,
104                    $name,
105                    $value_wrapper(self.0),
106                )
107            }
108
109            fn rebuild(self, cx: RebuildCx, state: &mut Self::State) {
110                state.rebuild(cx.parent, $name, $value_wrapper(self.0))
111            }
112        }
113    };
114}
115
116include!(concat!(env!("OUT_DIR"), "/gen_attr.rs"));