Coder Social home page Coder Social logo

yew-autoprops's People

Contributors

cecton avatar valyagolev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

cecton

yew-autoprops's Issues

Propless generic components require generic types to be used

Imagine a component like so:

#[autoprops_component]
pub fn Example<T: 'static>() -> Html {
    html! {}
}

As T is not used, Rust complains:

parameter `T` is never used
consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
  • Is Properties (generic) struct still generated despite having no props?

At least, currently solvable with following code:

#[autoprops_component]
pub fn Example<T: 'static>(#[prop_or_default] _never: &PhantomData<T>) -> Html {
    html! {}
}

Make generics work

As of writing the issue, yew-autoprops does not support generics.

Example 1:

#[autoprops_component]
pub fn Example<T: PartialEq + 'static>() -> Html {
    html! {
    }
}

#[function_component]
pub fn App() -> Html {
    html! {
        <Example<u64> />
    }
}

Errors:

struct takes 0 generic arguments but 1 generic argument was supplied

Probable reasons:

  • The generic clause is ignored altogether, and it is unable to build component struct generated by `#[function_component].
  • It fails to build Props instance with the supplied generic clause.

Example 2:

#[autoprops_component]
pub fn Example<T: PartialEq + 'static>(t: &T) -> Html {
    html! {
    }
}

#[function_component]
pub fn App() -> Html {
    html! {
        <Example<u64> t={ 0 } />
    }
}

Errors:

cannot find type `T` in this scope

Probable reasons:

  • Props struct is not supplied with the generic clause, so it does not know about the type T.

Possible solution

This appears to be solvable by copying the generic clause (<T: PartialEq + 'static>) over to both generated component fn (as-is) and generated Props struct (if individual generic parameters are used); as well as copying the clause to the component fn Props param's type, modified to contain only the type names (<T>).

Example 1:

#[derive(PartialEq, Properties)]
pub struct ExampleProps {
    // alternatively, `pub struct ExampleProps<T: PartialEq + 'static>`,
    // but then it would need `#[prop_or_default] pub T: PhantomData<T>` as a hack
}

#[function_component]
pub fn Example<T: PartialEq + 'static>(ExampleProps {}: &ExampleProps) -> Html {
    html! {
    }
}

#[function_component]
pub fn App() -> Html {
    html! {
        <Example<u64> />
    }
}

Example 2:

#[derive(PartialEq, Properties)]
pub struct ExampleProps<T: PartialEq + 'static> {
    t: T,
}

#[function_component]
pub fn Example<T: PartialEq + 'static>(ExampleProps { t }: &ExampleProps<T>) -> Html {
    html! {
    }
}

#[function_component]
pub fn App() -> Html {
    html! {
        <Example<u64> t={ 0 } />
    }
}

Main App cannot be autoprops

For consistency reasons, I tried to write following:

#[autoprops_component]
fn App() -> Html {
    html! {}
}

This comes up with following error on a CSR render:

the function or associated item `new` exists for struct `Renderer<App>`, but its trait bounds were not satisfied
the following trait bounds were not satisfied:
`AppProps: std::default::Default`
- doesn't satisfy `AppProps: std::default::Default`
- consider annotating `AppProps` with `#[derive(Default)]`: `#[derive(Default)]`

This is probably due to fact that props struct generates for App even if there are no props (as mentioned in #7).

  • Get rid of generating a props struct for propless autoprops components
  • Otherwise possibly make empty struct a Default? (Also, consider manual impl Default where all types are Default - this is possible by listing where type1: Default, type2: Default, no matter how simple or complex the type is - you can even type out where i32: Default and it will still work)

Generic components require generic types to be PartialEq

#[derive] is not perfect (funnily enough, I wrote this before I found the Rust blog quotation, where they mention it being "Perfect derive"), and Rust generates impls with that derived trait also present for generic parameters (e.g. derive(Clone) does impl<T: Clone> Clone for ...). This would happen even for instances when the requirement for the generic parameter is not required (e.g. an Rc<T> field means the struct does not actually require Clone on T).

yew-autoprops does #[derive(PartialEq)], which means when generating impls Rust will place such a requirement on the generic parameters as well. This means following example will not be valid:

#[autoprops_component]
pub fn Example<T>(something: Rc<T>) {
    html! {}
}

As it comes up with the following error:

can't compare `T` with `T`
no implementation for `T == T`
- required for `ExampleProps<T>` to implement `PartialEq`
- required by a bound in `Properties`
- consider further restricting type parameter `T`: `, T: std::cmp::PartialEq`

As all props fields are probably expected to be PartialEq (which isn't always the case with derive), I suggest manually implementing PartialEq for the props struct, containing comparisons for all the fields:

impl<T> PartialEq for ExampleProps<T> {
    fn eq(&self, other: &Self) -> bool {
        #pats_modified_1 = self; // adds _1 to each field, you also have to check that no name ends with _1/_2, otherwise add more underscores i guess
        #pats_modified_2 = other; // adds _2 to each field
        #comparisons // prop_1 == prop_2 && another_prop_1 == another_prop_2 && ...
    }
}

For generic parameters that are to be used directly as a type of a prop field, the user will have to declare them as PartialEq, which is the case for both derive and manual impl solutions.

This is a breaking problem (you cannot implement a custom PartialEq, unlike with non-autoprops props), and fixing it would improve experience of using generics by a lot compared to non-autoprops components.

Pattern binding for auto-props

As of writing, yew-autoprops does not support pattern-binding the props using the built-in @ operator (syntactically correct without the #[autoprops_component]):

#[derive(PartialEq)]
pub struct ExampleProp {
    i: u64,
}

#[autoprops_component]
pub fn Example(example_prop @ ExampleProp { i }: &ExampleProp) -> Html {
    html! {
    }
}

#[function_component]
pub fn App() -> Html {
    html! {
        <Example example_prop={ ExampleProp { i: 0 } } />
    }
}

Errors:

expected `:`, found `@`
the trait bound `ExampleProps: Properties` is not satisfied
no field `example_prop` on type `ExampleProps`

Possible Solution

Handle pattern after the @ operator.

#[derive(PartialEq)]
pub struct ExampleProp {
    i: u64,
}

#[derive(PartialEq, Properties)]
pub struct ExampleProps {
    example_prop: ExampleProp,
}

#[function_component]
pub fn Example(
    ExampleProps {
        // without the `example_prop @` the `example_prop` name will not be accessible in the function body
        example_prop: example_prop @ ExampleProp { i }, 
    }: &ExampleProps,
) -> Html {
    html! {
    }
}

#[function_component]
pub fn App() -> Html {
    html! {
        <Example example_prop={ ExampleProp { i: 0 } } />
    }
}

Attributes of function arguments should be applied to the function or to properties?

It is debatable of whether attributes of function arguments should be applied to the function itself or to properties struct definition. #[props_...] should be transferred to struct definition, however, I am not sure about other attributes.

All of the following order of attribute macros would result in different code generation behaviour to #[foreign_trait] if #[foreign_trait] will generate code based on #[foreign_trait_attr].

#[foreign_trait]
#[autoprops]
#[function_component]
fn Comp(#[foreign_trait_attr] arg: Arg) -> Html {}
#[autoprops]
#[foreign_trait]
#[function_component]
fn Comp(#[foreign_trait_attr] arg: Arg) -> Html {}
#[autoprops]
#[function_component]
#[foreign_trait]
fn Comp(#[foreign_trait_attr] arg: Arg) -> Html {}

(However, since this is not part of Yew, I am OK with leaving the implementation as-is and revisiting this in the future.)

Originally posted by @futursolo in #10 (comment)

#[autoprops_component] panics instead of making a proper error

As of writing, yew-autoprops uses panic!() macro to display errors to the user. This, however, is not intended and causes jarring error:

#[autoprops_component]
pub fn Example(i: u32) -> Html {
    html! {}
}

#[function_component]
pub fn App() -> Html {
    html! {
        <Example i={ 0 } />
    }
}

Error:

custom attribute panicked
message: Invalid argument: i : u32 (must be a reference)

Possible Solutions

  • Generate compile_error!() instead of panic!()ing, this should cause a proper simple error to be displayed to the user of the library.
  • In future, as Rust features stabilize, consider using Diagnostic API.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.