This is unreleased documentation for Yew Next version.
For up-to-date documentation, see the latest version on docs.rs.

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    #[diagnostic::on_unimplemented(
29        message = "property `{P}` is required but not provided",
30        label = "missing required property `{P}`"
31    )]
32    pub trait HasProp<P, How> {}
33
34    /// A marker trait to ensure that the builder has received all required props.
35    /// For each struct deriving [`Properties`], an impl is generated, requiring `HasProp<p>` for
36    /// all properties marked as required as a bound on the impl.
37    ///
38    /// [`Properties`]: super::Properties
39    #[diagnostic::on_unimplemented(
40        message = "not all required properties have been provided for `{P}`",
41        label = "missing required properties"
42    )]
43    pub trait HasAllProps<P, How> {}
44
45    /// Trait finishing the builder and verifying all props were set.
46    /// The structure can be a bit surprising, and is related to how the proc macro reports errors
47    /// - why have a prepare_build method? This captures the argument types, but now `How`, and
48    ///   returns an internal type with a method that can be called without further qualification.
49    ///   We need the additional types, to avoid collision with property names in the Builder. We
50    ///   want to avoid qualification to persuade rust not to report the `finish_build` method name.
51    /// - why have a AllPropsFor trait? We want the trait to be on the Token, not on a type
52    ///   associated or derived from it, so that it shows up in errors directly instead of through
53    ///   convoluted traces.
54    pub trait Buildable<Token> {
55        /// Property type being built
56        type Output;
57        /// Instead of `Token` directly, a wrapped token type is checked for trait impls in macro
58        /// code. This avoids problems related to blanket impls.
59        type WrappedToken;
60        /// This method "captures" the builder and token type, but does not verify yet.
61        fn prepare_build(builder: Self, _: &Token) -> PreBuild<Token, Self>
62        where
63            Self: Sized,
64        {
65            PreBuild {
66                builder,
67                _token: std::marker::PhantomData,
68            }
69        }
70        /// Build the props from self. Expected to panic if not all props where set.
71        fn build(this: Self) -> Self::Output;
72    }
73    /// Helper alias for a Builder, also capturing the prop Token recording the provided props.
74    #[derive(Debug)]
75    pub struct PreBuild<Token, B> {
76        _token: std::marker::PhantomData<Token>,
77        builder: B,
78    }
79
80    impl<Token, B: Buildable<Token>> PreBuild<Token, B> {
81        /// This is the method that introduces the actual bound verifying all props where set.
82        pub fn build<How>(self) -> B::Output
83        where
84            Token: AllPropsFor<B, How>,
85        {
86            B::build(self.builder)
87        }
88    }
89
90    /// Trait to specify the requirement for Self to be a valid token signaling all props have been
91    /// provided to the builder.
92    #[diagnostic::on_unimplemented(
93        message = "not all required properties have been provided",
94        label = "missing required properties for this component"
95    )]
96    pub trait AllPropsFor<Builder, How> {}
97
98    impl<Token, Builder: Buildable<Token>, How> AllPropsFor<Builder, How> for Token where
99        Builder::WrappedToken: HasAllProps<Builder::Output, How>
100    {
101    }
102
103    /// Dummy struct targeted by assertions that all props were set
104    #[derive(Debug)]
105    pub struct AssertAllProps;
106
107    /// Builder for when a component has no properties
108    #[derive(Debug, PartialEq, Eq)]
109    pub struct EmptyBuilder;
110
111    impl super::Properties for () {
112        type Builder = EmptyBuilder;
113
114        fn builder() -> Self::Builder {
115            EmptyBuilder
116        }
117    }
118
119    impl<T> Buildable<T> for EmptyBuilder {
120        type Output = ();
121        type WrappedToken = ();
122
123        /// Build empty properties
124        fn build(_: Self) {}
125    }
126
127    impl<T> HasAllProps<(), T> for T {}
128}
129
130#[doc(hidden)]
131pub use __macro::{AllPropsFor, AssertAllProps, Buildable, HasAllProps, HasProp};