Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

self not usable if using a macro in view! #189

Open
antoyo opened this issue Feb 3, 2020 · 5 comments
Open

self not usable if using a macro in view! #189

antoyo opened this issue Feb 3, 2020 · 5 comments
Milestone

Comments

@antoyo
Copy link
Owner

antoyo commented Feb 3, 2020

view! {
    gtk::Label {
        text: &format!("{}", self.model.counter),
    },
}
@sanpii
Copy link
Contributor

sanpii commented Feb 25, 2020

Is there a workaround for this issue?

@antoyo
Copy link
Owner Author

antoyo commented Feb 25, 2020

Maybe something like this:

view! {
    gtk::Label {
        text: {
            let counter = &self.model.counter;
            &format!("{}", counter)
        },
    },
}

@antoyo antoyo added this to the 1.0 milestone Nov 29, 2020
@antoyo antoyo added medium and removed easy labels Nov 29, 2020
@antoyo
Copy link
Owner Author

antoyo commented Nov 29, 2020

This seems non-trivial to fix and the above workaround doesn't work.

As macro arguments can be anything, even invalid Rust code, it makes it very hard to actually parse them to find usage of self.model.

Does anyone have any solution to this problem?

What macros do you use in this context?
Maybe we could only support a limited set of macros, like format!.

@sanpii
Copy link
Contributor

sanpii commented Nov 29, 2020

A minimalist example to reproduce this bug:

use gtk::GtkWindowExt;
use relm::Widget;

#[relm_derive::widget]
impl Widget for Win {
    fn model() -> String {
        "#189".to_string()
    }

    fn update(&mut self, _: ()) {
    }

    view! {
        gtk::Window {
            title: &format!("{}", self.model),
        }
    }
}

fn main() {
    Win::run(()).expect("Win::run failed");
}
cargo check
$ cg check
    Checking rust v0.1.0 (/home/sanpi/test/rust)
error[E0424]: expected value, found module `self`
  --> src/main.rs:15:35
   |
5  | impl Widget for Win {
   |                 --- this function doesn't have a `self` parameter
...
15 |             title: &format!("{}", self.model),
   |                                   ^^^^ `self` value is a keyword only available in methods with a `self` parameter
   |
help: add a `self` receiver parameter to make the associated `fn` a method
   |
5  | impl Widget for &self, Win {
   |                 ^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0424`.
error: could not compile `rust`

To learn more, run the command again with --verbose.
cargo explain
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate std;
use gtk::GtkWindowExt;
use relm::Widget;
#[allow(dead_code, missing_docs)]
pub struct Win {
    gtkwindow1: gtk::Window,
    model: String,
}
pub struct __WinWidgets {
    pub gtkwindow1: gtk::Window,
}
impl Widget for Win {
    #[allow(unused_variables)]
    fn view(relm: &::relm::Relm<Self>, __relm_model: Self::Model) -> Self {
        let gtkwindow1: gtk::Window = unsafe {
            if !gtk::is_initialized_main_thread() {
                if gtk::is_initialized() {
                    {
                        ::std::rt::begin_panic("GTK may only be used from the main thread.")
                    };
                } else {
                    {
                        ::std::rt::begin_panic(
                            "GTK has not been initialized. Call `gtk::init` first.",
                        )
                    };
                }
            }
            use relm::StaticType;
            use relm::{Cast, FromGlibPtrNone};
            let values: &[::relm::Value] = &[];
            let mut parameters = [];
            ::gtk::Widget::from_glib_none(::relm::g_object_newv(
                ::relm::ToGlib::to_glib(&gtk::Window::static_type()),
                0u32,
                parameters.as_mut_ptr(),
            ) as *mut _)
            .downcast()
            .unwrap()
        };
        gtkwindow1.set_title(&{
            let res = ::alloc::fmt::format(::core::fmt::Arguments::new_v1(
                &[""],
                &match (&self.model,) {
                    (arg0,) => [::core::fmt::ArgumentV1::new(
                        arg0,
                        ::core::fmt::Display::fmt,
                    )],
                },
            ));
            res
        });
        ::gtk::WidgetExt::show(&gtkwindow1);
        Win {
            gtkwindow1: gtkwindow1,
            model: __relm_model,
        }
    }
    type Root = gtk::Window;
    fn root(&self) -> Self::Root {
        self.gtkwindow1.clone()
    }
}
impl ::relm::Update for Win {
    type Msg = ();
    type Model = String;
    type ModelParam = ();
    fn update(&mut self, _: ()) {}
    fn model(_: &::relm::Relm<Self>, _: ()) -> String {
        "#189".to_string()
    }
}
impl ::relm::WidgetTest for Win {
    type Widgets = __WinWidgets;
    fn get_widgets(&self) -> __WinWidgets {
        __WinWidgets {
            gtkwindow1: self.gtkwindow1.clone(),
        }
    }
}
impl Win {}
fn main() {
    Win::run(()).expect("Win::run failed");
}

Using __relm_model works fine.

Some ideas:

  1. Rename __relm_model to model;
  2. Allow only self.model and replace it by __relm_model;
  3. Add an argument to view!:
view!(model) {
    gtk::Window {
        title: &format!("{}", model),
    }
}

I like the second one, but it maybe not the easier…

@antoyo
Copy link
Owner Author

antoyo commented Nov 29, 2020

If we were to choose the second option, how would that be implemented?
By iterating over all the tokens in the macro and replacing the appropriate sequence of tokens (self, ., models) by __relm_model everywhere?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants