Skip to content

Commit

Permalink
add documentation and last adjustements
Browse files Browse the repository at this point in the history
  • Loading branch information
WorldSEnder committed Jun 12, 2022
1 parent ec348ec commit 38092c0
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 69 deletions.
2 changes: 1 addition & 1 deletion packages/yew-macro/src/derive_props/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ impl PropsBuilder<'_> {
#[automatically_derived]
impl #impl_generics ::yew::html::Buildable< #token_arg > for #builder_name<#generic_args> #where_clause {
type Output = #props_name #ty_generics;
type WrappedTok = #check_all_props_name< #token_arg >;
type WrappedToken = #check_all_props_name< #token_arg >;
fn build(this: Self) -> Self::Output {
#props_name #turbofish_generics {
#(#set_fields)*
Expand Down
2 changes: 1 addition & 1 deletion packages/yew-macro/src/props/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ impl ComponentProps {
}
});
let build_builder = quote_spanned! {props_ty.span()=>
::yew::html::Buildable::pre_build(#builder_ident, &#token_ident).build()
::yew::html::Buildable::prepare_build(#builder_ident, &#token_ident).build()
};

quote! {
Expand Down
2 changes: 1 addition & 1 deletion packages/yew-macro/tests/derive_props/fail.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ note: required because of the requirements on the impl of `HasAllProps<t3::Props
|
29 | #[derive(Clone, Properties, PartialEq)]
| ^^^^^^^^^^
= note: required because of the requirements on the impl of `AllPropsFrom<AssertAllProps, t3::PropsBuilder, (_,)>` for `AssertAllProps`
= note: required because of the requirements on the impl of `AllPropsFor<t3::PropsBuilder, (_,)>` for `AssertAllProps`
= note: this error originates in the derive macro `Properties` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `Value: Default` is not satisfied
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ note: required because of the requirements on the impl of `HasAllProps<Props, (_
|
3 | #[derive(Clone, Properties, PartialEq)]
| ^^^^^^^^^^
= note: required because of the requirements on the impl of `AllPropsFrom<AssertAllProps, PropsBuilder, (_,)>` for `AssertAllProps`
= note: required because of the requirements on the impl of `AllPropsFor<PropsBuilder, (_,)>` for `AssertAllProps`
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0599]: the function or associated item `new` exists for struct `VChild<Comp<MissingTypeBounds>>`, but its trait bounds were not satisfied
Expand Down
6 changes: 3 additions & 3 deletions packages/yew-macro/tests/html_macro/component-fail.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ note: required because of the requirements on the impl of `HasAllProps<ChildProp
|
4 | #[derive(Clone, Properties, PartialEq)]
| ^^^^^^^^^^
= note: required because of the requirements on the impl of `AllPropsFrom<AssertAllProps, ChildPropertiesBuilder, (_,)>` for `AssertAllProps`
= note: required because of the requirements on the impl of `AllPropsFor<ChildPropertiesBuilder, (_,)>` for `AssertAllProps`
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0599]: no method named `children` found for struct `ChildPropertiesBuilder` in the current scope
Expand All @@ -430,7 +430,7 @@ note: required because of the requirements on the impl of `HasAllProps<ChildCont
|
24 | #[derive(Clone, Properties, PartialEq)]
| ^^^^^^^^^^
= note: required because of the requirements on the impl of `AllPropsFrom<AssertAllProps, ChildContainerPropertiesBuilder, (_,)>` for `AssertAllProps`
= note: required because of the requirements on the impl of `AllPropsFor<ChildContainerPropertiesBuilder, (_,)>` for `AssertAllProps`
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `AssertAllProps: HasProp<_ChildContainerProperties::children, _>` is not satisfied
Expand All @@ -444,7 +444,7 @@ note: required because of the requirements on the impl of `HasAllProps<ChildCont
|
24 | #[derive(Clone, Properties, PartialEq)]
| ^^^^^^^^^^
= note: required because of the requirements on the impl of `AllPropsFrom<AssertAllProps, ChildContainerPropertiesBuilder, (_,)>` for `AssertAllProps`
= note: required because of the requirements on the impl of `AllPropsFor<ChildContainerPropertiesBuilder, (_,)>` for `AssertAllProps`
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `VChild<Child>: From<yew::virtual_dom::VText>` is not satisfied
Expand Down
149 changes: 87 additions & 62 deletions packages/yew/src/html/component/properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,81 +11,106 @@ pub trait Properties: PartialEq {
fn builder() -> Self::Builder;
}

/// A marker trait to ensure that the builder has received a specific required prop
#[doc(hidden)]
pub trait HasProp<P, How> {}

/// A marker trait to ensure that the builder has received all required props
#[doc(hidden)]
pub trait HasAllProps<P, How> {}
mod macro_export {
/// A marker trait to ensure that the builder has received a specific required prop.
/// For each required impl in a property, we generate:
/// - a struct with the name of the prop, which takes the place of `P`.
/// - a token wrapper, `HasP<TokenTail>`, that records that the build state represented includes
/// the state in `TokenTail` + `P`. Such tokens are returned from the setter on the builder,
/// to verify the build state.
/// - An `impl<T> HasP<T>: HasProp<P, _>` saying that a state represented by a token of
/// `HasP<_>` indeed verifies P has been set.
/// - An `impl<Q> HasP<Tail>: HasProp<Q, _> where Tail: HasProp<Q>` saying that any props set
/// previously (represented by the tail) is still set after P has been set.
/// - ^ the two impls would be overlapping, where it not for the `How` argument, which resolves
/// the conflict.
pub trait HasProp<P, How> {}

/// A marker trait to ensure that the builder has received all required props.
/// For each struct deriving [`Properties`], an impl is generated, requiring `HasProp<p>` for
/// all properties marked as required as a bound on the impl.
pub trait HasAllProps<P, How> {}

/// Trait finishing the builder and verifying all props were set.
/// The structure can be a bit surprising, and is related to how the proc macro reports errors
/// - why have a prepare_build method? This captures the argument types, but now `How`, and
/// returns an internal type with a method that can be called without further qualification.
/// We need the additional types, to avoid collision with property names in the Builder. We
/// want to avoid qualification to persuade rust not to report the `finish_build` method name.
/// - why have a AllPropsFor trait? We want the trait to be on the Token, not on a type
/// associated or derived from it, so that it shows up in errors directly instead of through
/// convoluted traces.
pub trait Buildable<Token> {
/// Property type being built
type Output;
/// Instead of `Token` directly, a wrapped token type is checked for trait impls in macro
/// code. This avoids problems related to blanket impls.
type WrappedToken;
/// This method "captures" the builder and token type, but does not verify yet.
fn prepare_build(builder: Self, _: &Token) -> PreBuild<Token, Self>
where
Self: Sized,
{
PreBuild {
builder,
_token: std::marker::PhantomData,
}
}
/// Build the props from self. Expected to panic if not all props where set.
fn build(this: Self) -> Self::Output;
}
/// Helper alias for a Builder, also capturing the prop Token recording the provided props.
#[derive(Debug)]
pub struct PreBuild<Token, B> {
_token: std::marker::PhantomData<Token>,
builder: B,
}

/// Trait finishing the builder and verifying all props were set
#[doc(hidden)]
pub trait Buildable<Token: ?Sized> {
type Output;
type WrappedTok;
fn pre_build(builder: Self, _: &Token) -> PreBuild<Token, Self>
where
Self: Sized,
{
PreBuild {
builder,
_token: std::marker::PhantomData,
impl<Token, B: Buildable<Token>> PreBuild<Token, B> {
/// This is the method that introduces the actual bound verifying all props where set.
pub fn build<How>(self) -> B::Output
where
Token: AllPropsFor<B, How>,
{
B::build(self.builder)
}
}
fn build(this: Self) -> Self::Output;
}
#[doc(hidden)]
#[derive(Debug)]
pub struct PreBuild<Token: ?Sized, B> {
_token: std::marker::PhantomData<Token>,
builder: B,
}

impl<Token, B: Buildable<Token>> PreBuild<Token, B> {
#[doc(hidden)]
pub fn build<How>(self) -> B::Output
where
Token: AllPropsFrom<Token, B, How>,
/// Trait to specify the requirement for Self to be a valid token signaling all props have been
/// provided to the builder.
pub trait AllPropsFor<Builder, How> {}

impl<Token, Builder: Buildable<Token>, How> AllPropsFor<Builder, How> for Token where
Builder::WrappedToken: HasAllProps<Builder::Output, How>
{
B::build(self.builder)
}
}

#[doc(hidden)]
pub trait AllPropsFrom<Token, B: Buildable<Token>, How> {}
/// Dummy struct targeted by assertions that all props were set
#[derive(Debug)]
pub struct AssertAllProps;

impl<Token, B, How> AllPropsFrom<Token, B, How> for Token
where
B: Buildable<Token>,
B::WrappedTok: HasAllProps<B::Output, How>,
{
}
/// Builder for when a component has no properties
#[derive(Debug, PartialEq)]
pub struct EmptyBuilder;

/// Dummy struct targeted by assertions that all props were set
#[doc(hidden)]
#[derive(Debug)]
pub struct AssertAllProps;
impl super::Properties for () {
type Builder = EmptyBuilder;

/// Builder for when a component has no properties
#[derive(Debug, PartialEq)]
#[doc(hidden)]
pub struct EmptyBuilder;
fn builder() -> Self::Builder {
EmptyBuilder
}
}

impl Properties for () {
type Builder = EmptyBuilder;
impl<T> Buildable<T> for EmptyBuilder {
type Output = ();
type WrappedToken = ();

fn builder() -> Self::Builder {
EmptyBuilder
/// Build empty properties
fn build(_: Self) {}
}
}

impl<T> Buildable<T> for EmptyBuilder {
type Output = ();
type WrappedTok = ();

/// Build empty properties
fn build(_: Self) {}
impl<T> HasAllProps<(), T> for T {}
}

impl<T> HasAllProps<(), T> for T {}
#[doc(hidden)]
pub use macro_export::{AllPropsFor, AssertAllProps, Buildable, HasAllProps, HasProp};

0 comments on commit 38092c0

Please sign in to comment.