yew/html/component/properties.rs
1//! Component properties module
2
3pub use yew_macro::Properties;
4
5/// Trait for building properties for a component
6pub trait Properties: PartialEq {
7 /// Builder that will be used to construct properties
8 type Builder;
9
10 /// Entrypoint for building properties
11 fn builder() -> Self::Builder;
12}
13
14#[doc(hidden)]
15mod __macro {
16 /// A marker trait to ensure that the builder has received a specific required prop.
17 /// For each required impl in a property, we generate:
18 /// - a struct with the name of the prop, which takes the place of `P`.
19 /// - a token wrapper, `HasP<TokenTail>`, that records that the build state represented includes
20 /// the state in `TokenTail` + `P`. Such tokens are returned from the setter on the builder,
21 /// to verify the build state.
22 /// - An `impl<T> HasP<T>: HasProp<P, _>` saying that a state represented by a token of
23 /// `HasP<_>` indeed verifies P has been set.
24 /// - An `impl<Q> HasP<Tail>: HasProp<Q, _> where Tail: HasProp<Q>` saying that any props set
25 /// previously (represented by the tail) is still set after P has been set.
26 /// - ^ the two impls would be overlapping, where it not for the `How` argument, which resolves
27 /// the conflict.
28 pub trait HasProp<P, How> {}
29
30 /// A marker trait to ensure that the builder has received all required props.
31 /// For each struct deriving [`Properties`], an impl is generated, requiring `HasProp<p>` for
32 /// all properties marked as required as a bound on the impl.
33 ///
34 /// [`Properties`]: super::Properties
35 pub trait HasAllProps<P, How> {}
36
37 /// Trait finishing the builder and verifying all props were set.
38 /// The structure can be a bit surprising, and is related to how the proc macro reports errors
39 /// - why have a prepare_build method? This captures the argument types, but now `How`, and
40 /// returns an internal type with a method that can be called without further qualification.
41 /// We need the additional types, to avoid collision with property names in the Builder. We
42 /// want to avoid qualification to persuade rust not to report the `finish_build` method name.
43 /// - why have a AllPropsFor trait? We want the trait to be on the Token, not on a type
44 /// associated or derived from it, so that it shows up in errors directly instead of through
45 /// convoluted traces.
46 pub trait Buildable<Token> {
47 /// Property type being built
48 type Output;
49 /// Instead of `Token` directly, a wrapped token type is checked for trait impls in macro
50 /// code. This avoids problems related to blanket impls.
51 type WrappedToken;
52 /// This method "captures" the builder and token type, but does not verify yet.
53 fn prepare_build(builder: Self, _: &Token) -> PreBuild<Token, Self>
54 where
55 Self: Sized,
56 {
57 PreBuild {
58 builder,
59 _token: std::marker::PhantomData,
60 }
61 }
62 /// Build the props from self. Expected to panic if not all props where set.
63 fn build(this: Self) -> Self::Output;
64 }
65 /// Helper alias for a Builder, also capturing the prop Token recording the provided props.
66 #[derive(Debug)]
67 pub struct PreBuild<Token, B> {
68 _token: std::marker::PhantomData<Token>,
69 builder: B,
70 }
71
72 impl<Token, B: Buildable<Token>> PreBuild<Token, B> {
73 /// This is the method that introduces the actual bound verifying all props where set.
74 pub fn build<How>(self) -> B::Output
75 where
76 Token: AllPropsFor<B, How>,
77 {
78 B::build(self.builder)
79 }
80 }
81
82 /// Trait to specify the requirement for Self to be a valid token signaling all props have been
83 /// provided to the builder.
84 pub trait AllPropsFor<Builder, How> {}
85
86 impl<Token, Builder: Buildable<Token>, How> AllPropsFor<Builder, How> for Token where
87 Builder::WrappedToken: HasAllProps<Builder::Output, How>
88 {
89 }
90
91 /// Dummy struct targeted by assertions that all props were set
92 #[derive(Debug)]
93 pub struct AssertAllProps;
94
95 /// Builder for when a component has no properties
96 #[derive(Debug, PartialEq, Eq)]
97 pub struct EmptyBuilder;
98
99 impl super::Properties for () {
100 type Builder = EmptyBuilder;
101
102 fn builder() -> Self::Builder {
103 EmptyBuilder
104 }
105 }
106
107 impl<T> Buildable<T> for EmptyBuilder {
108 type Output = ();
109 type WrappedToken = ();
110
111 /// Build empty properties
112 fn build(_: Self) {}
113 }
114
115 impl<T> HasAllProps<(), T> for T {}
116}
117
118#[doc(hidden)]
119pub use __macro::{AllPropsFor, AssertAllProps, Buildable, HasAllProps, HasProp};