self not usable if using a macro in view!
view! {
gtk::Label {
text: &format!("{}", self.model.counter),
},
}
Is there a workaround for this issue?
Maybe something like this:
view! {
gtk::Label {
text: {
let counter = &self.model.counter;
&format!("{}", counter)
},
},
}
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!.
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(>k::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(>kwindow1);
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:
- Rename
__relm_modeltomodel; - Allow only
self.modeland replace it by__relm_model; - Add an argument to
view!:
view!(model) {
gtk::Window {
title: &format!("{}", model),
}
}
I like the second one, but it maybe not the easier…
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?