Add callback to element generated inside iterable - rust

I'm trying to generate HTML of elements inside of a vector, which will have a button to remove itself (the button). Here is my code:
pub struct App {
pub elements: Vec<AppElement>
}
pub struct AppElement {}
impl Component for App {
// ..
fn view(&self, ctx: &Context<Self>) -> Html {
let elements = self.elements.iter().map(|e| html! {
<button onclick={ ctx.link().callback(|_| AppMsg::RemoveElement(e)) }>
{ "Remove" }
</button>
}).collect::<Html>();
html! {
{ elements }
}
}
}
This code does not compile because the anonymous lifetime of iter() does not outlive the required static lifetime. Is there a way to achieve what I'm trying to do?

Related

Need help creating a plugin system for the game engine

Github repository
A little about how the plugin system should roughly work.
The Plugin trait implements the build() method, which is called when the plugin is loaded. The build() method takes App struct, where App is the application structure.
Now my code looks cumbersome. So the question is, are there any other options?
pub trait Component {
fn start(&mut self);
fn update(&mut self);
}
pub struct App {
runners: Vec<Box<dyn Fn(&mut App)>>,
components: Vec<Box<dyn Component>>,
}
&mut App
Initially, the build() method took &mut App, but this did not allow me to do the following:
impl Plugin for WinitWSIPlugin {
fn build(&self, app: &mut App) {
app.set_runner(move || {
// Error here
app.open_window(...);
});
}
}
As I understood the compiler did not allow me to do this, because I passed a reference to the App structure, which may soon be irrelevant.
Rc<RefCell>
In the following implementation, I passed Rc<RefCell<App>>, but calling borrow_mut() to call open_window(...) had a panic, even though I had not manually called borrow_mut() before.
impl Plugin for WinitWSIPlugin {
fn build(&self, app: Rc<RefCell<App>>) {
app.clone().borrow().set_runner(move || {
let AppSystem::Windowed { info } = app.borrow().system();
let mut winit_windows = WinitWindows::default();
let event_loop = winit::event_loop::EventLoop::new();
/*===== Panic this =====*/
app.borrow_mut().open_window(winit_windows.create_window(
&event_loop,
app.borrow().id(),
&info,
));
});
}
}
The last revision I stopped at.
Using Mutex in those fields of the App structure that will be used in the plugins. That way, I won't have to call borrow_mut() even if I need to change the value. It will be enough to call borrow()
impl Plugin for WinitWSIPlugin {
fn build(&self, app: Rc<RefCell<App>>) {
app.clone().borrow().set_runner(move || {
let AppSystem::Windowed { info } = app.borrow().system();
let mut winit_windows = WinitWindows::default();
let event_loop = winit::event_loop::EventLoop::new();
app.borrow().open_window(winit_windows.create_window(
&event_loop,
app.borrow().id(),
&info,
));
for component in app.borrow().components().borrow_mut().iter_mut() {
component.init(app.clone());
}
let app = app.clone();
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
for component in app.borrow().components().borrow_mut().iter_mut() {
component.update(app.clone());
}
match event {
winit::event::Event::WindowEvent {
window_id: _,
event,
} => match event {
winit::event::WindowEvent::CloseRequested => control_flow.set_exit(),
_ => (),
},
_ => (),
}
});
});
}
}
You could get around having to share App (which I'm not sure will work anyways) by just passing it into the closure as a parameter:
struct App {
runners: Vec<Box<dyn Fn(&mut App)>>,
}
impl App {
fn set_runner(&mut self, f: impl Fn(&mut App) + 'static) {
self.runners.push(Box::new(f));
}
fn run(&mut self) {
// take the runners out of self to avoid borrow & mutable borrow at the same time
let runners = std::mem::take(&mut self.runners);
for runner in runners.iter() {
// pass self into the runner so it can change app state and create windows etc
runner(self);
}
// put the runners back.
self.runners = runners;
}
fn open_window(&mut self) {}
}
trait Plugin {
fn build(&self, app: &mut App);
}
struct WinitWSIPlugin;
impl Plugin for WinitWSIPlugin {
fn build(&self, app: &mut App) {
// the closure now takes a `&mut App` as parameter
// the argument type is optional and just shown for demonstration here
app.set_runner(move |app: &mut App| {
app.open_window();
});
}
}

Understanding wasm-bindgen returned objects memory management

I'm trying to return a typed object from Rust to Typescript, and I ideally don't want to have to manually manage memory (performance is not the highest priority). While doing this, I'm trying to understand the generated JS.
Rust:
#[wasm_bindgen]
pub fn retjs() -> JsValue {
// in my actual project I serialize a struct with `JsValue::from_serde`
JsValue::from_str("")
}
#[wasm_bindgen]
pub fn retstruct() -> A {
A {
a: "".to_owned(),
};
}
#[wasm_bindgen]
pub struct A {
a: String,
}
#[wasm_bindgen]
impl A {
#[wasm_bindgen]
pub fn foo(&self) -> String {
return self.a.clone();
}
}
Generated JS:
export function retjs() {
const ret = wasm.retjs();
return takeObject(ret);
}
function takeObject(idx) {
const ret = getObject(idx);
dropObject(idx);
return ret;
}
function dropObject(idx) {
if (idx < 36) return;
heap[idx] = heap_next;
heap_next = idx;
}
export function retstruct() {
const ret = wasm.retstruct();
return A.__wrap(ret);
}
// generated class A omitted for brevity. Here relevant that it has a `free()` method.
Is my understanding correct that with the JsValue the memory is completely freed automatically? And that I've to do this manually with the struct? Is there a way to get around that?
I basically just want type safety in Typescript, so when I update the struct in Rust the Typescript code is automatically updated.

Create macro to simplify declaration of deeply nested enum?

I want to use deeply nested enums to represent blocks in my game:
enum Element { Void, Materal(Material) }
enum Material { Gas(Gas), NonGas(NonGas) }
enum NonGas { Liquid(Liquid), Solid(Solid) }
enum Solid { MovableSolid(MovableSolid), ImmovableSolid(ImmovableSolid) }
enum Gas { Smoke }
enum Liquid { Water }
enum ImmovableSolid { Bedrock }
enum MovableSolid { Sand, GunPowder }
I found it very verbose to declare an Element:
let block: Element = Element::Materal(Material::NonGas(NonGas::Solid(Solid::ImmovableSolid(ImmovableSolid::Bedrock))));
Is it possible to create a macro to add syntactic sugar for my enum declaration?
I'm hoping to create a macro that can automagically resolve the enum path, for example
let block: Element = NewElement!(ImmovableSolid::Bedrock);
Using cdhowie's From idea, I think you'd only need trait impls from your lowest level enums. You can skip ones like impl From<Material> for Element because you need a child to create a Material, so it doesn't really make sense to start at that level.
impl From<Gas> for Element {
fn from(e: Gas) -> Element {
Element::Materal(Material::Gas(e))
}
}
impl From<Liquid> for Element {
fn from(e: Liquid) -> Element {
Element::Materal(Material::NonGas(NonGas::Liquid(e)))
}
}
impl From<ImmovableSolid> for Element {
fn from(e: ImmovableSolid) -> Element {
Element::Materal(Material::NonGas(NonGas::Solid(Solid::ImmovableSolid(e))))
}
}
impl From<MovableSolid> for Element {
fn from(e: MovableSolid) -> Element {
Element::Materal(Material::NonGas(NonGas::Solid(Solid::MovableSolid(e))))
}
}
fn main() {
println!("{:?}", Element::from(ImmovableSolid::Bedrock));
}

Pass an mutable instance method to a function

I am teaching myself Rust by creating a toy SDL2 lib for myself.
I created something similar in Go and am trying to port my code across. So far, this is the problem I cannot overcome. I want my library to have callback to a function on the program state so I can have keyboard events sent from my library code to my client code.
The aim is for the keydown events from the SDL keyboard event pump should trigger the on_keydown function on the state object. If I remove the State struct and just use static functions then it works. Of course this prevents me from changing the state of the program based on keyboard actions.
I am trying to use external crates as little as possible.
The relevant parts of the library.
pub enum GameCommand {
Quit,
Continue,
}
pub struct Window {
keydown_event: fn(Event) -> GameCommand,
}
impl Window {
pub fn set_keydown_event(&mut self, f: fn(e: Event) -> GameCommand) {
self.keydown_event = f;
}
pub fn run(&mut self) -> Result<(), String> {
let mut event_pump = self.game.context.event_pump()?;
'running: loop {
// Handle events
for event in event_pump.poll_iter() {
let mut gc = GameCommand::Continue;
match event {
Event::Quit { .. } => break 'running,
Event::KeyDown { repeat: false, .. } => {
gc = (self.keydown_event)(event);
}
_ => {}
}
if let GameCommand::Quit = gc {
break 'running
}
}
}
Ok(())
}
}
Now the relevant part of the client bin.
struct State {
bgcolor: Color,
}
impl State {
fn on_keydown(&mut self, event: Event) -> GameCommand {
match event {
Event::KeyDown { keycode: Some(Keycode::R), .. } => {
self.bgcolor.r += 1;
GameCommand::Continue
},
Event::KeyDown { keycode: Some(Keycode::G), .. } => {
self.bgcolor.g += 1;
GameCommand::Continue
},
Event::KeyDown { keycode: Some(Keycode::B), .. } => {
self.bgcolor.b += 1;
GameCommand::Continue
},
Event::KeyDown { keycode: Some(Keycode::Escape), ..} => {
GameCommand::Quit
},
_ => GameCommand::Continue,
}
}
}
Now the main function.
fn main() -> Result<(), String> {
let mut state = State {
bgcolor: Color::RGB(0, 0, 0),
};
let mut window = Window::new();
window.set_keydown_event(state.on_keydown);
Ok(())
}
There is a far bit of code skipped to keep it shortish. The error I get with this code is.
{
"code": "E0615",
"message": "attempted to take value of method `on_keydown` on type `State`\n\nmethod, not a field\n\nhelp: use parentheses to call the method: `(_)`",
}
If I window.set_keydown_event(state.on_keydown); I get this error.
{
"code": "E0308",
"message": "mismatched types\n\nexpected fn pointer, found enum `sdlgame::GameCommand`\n\nnote: expected fn pointer `fn(sdl2::event::Event) -> sdlgame::GameCommand`\n found enum `sdlgame::GameCommand`",
}
I assume the problem is the difference in function signatures. In the set_keydown_event function it expects.
fn(Event) -> GameCommand
Which is why a plain function not associated with a struct works. For the instance method to mutate state it requires the signature.
fn on_keydown(&mut self, event: Event) -> GameCommand
Initially, I am trying to achieve this is a single threaded manner as I am trying to keep things simple for me to reason out. Multi-threading will come later.
Is this possible in Rust and what is the correct way of achieving this result?
Thanks in advance.
Basically, you need to use function traits as well as an explicit closure so the call is bound to the variable. So, you'd change your Window to use a function trait:
// F is now the function type
pub struct Window<F: FnMut(Event) -> GameCommand> {
keydown_event: F,
}
Then you'd change your impl to support that function trait:
// put generic in impl
impl<F: FnMut(Event) -> GameCommand> Window<F> {
// take F as the parameter type now
pub fn set_keydown_event(&mut self, f: F) {
self.keydown_event = f;
}
pub fn run(&mut self) -> Result<(), String> {
// this function should stay the same
}
}
Then, you'd pass an explicit closure to it:
fn main() -> Result<(), String> {
let mut state = State {
bgcolor: Color::RGB(0, 0, 0),
};
let mut window = Window::new();
// binds the on_keydown function to the state variable
window.set_keydown_event(|x| state.on_keydown(x));
Ok(())
}

Can I use loops inside a Rust Mustache MapBuilder?

Is it possible to use loops inside a Rust Mustache (https://github.com/erickt/rust-mustache) MapBuilder to populate the contents of the vector? I've attached a semi-working example, it works with the struct version but not with the builder version.
Edit: The code compiles now thanks to Paul. I was missing two things: |mut builder| and builder = builder.push_map.
The thing is I do not want to use the struct version as I'll need to iterate over the images vector and mutate an item based on an certain condition (and I don't want to change the original vector).
I've looked here https://github.com/erickt/rust-mustache/blob/master/src/builder.rs but none of these code snippets show a loop example. Either it is not possible or I'm doing something wrong. I also created an issue but the erickt doesn't seem very active there.
Thank you.
main.rs:
extern crate serialize;
// [dependencies.rust-mustache]
//
// # git = "https://github.com/erickt/rust-mustache.git"
// git = "https://github.com/tsurai/rust-mustache.git"
extern crate mustache;
mod with_struct;
mod with_builder;
fn main() {
with_struct::go();
with_builder::go();
}
with_builder.rs:
use std::io;
use mustache;
use mustache::MapBuilder;
struct Image {
name: String,
file: String
}
impl Image {
fn new(name: &str, file: &str) -> Image {
Image {
name: String::from_str(name),
file: String::from_str(file)
}
}
}
pub fn go() {
let images = load_images();
let template = mustache::compile_str(template());
let data = MapBuilder::new()
.insert_vec("images", |mut builder| {
// ^~~~~ Need mutableb builder
for image in images.iter() {
builder = builder.push_map(|builder| {
// ^~~~~~~~~~^~~~~ Need to re-assign the builder
builder
.insert_str("name", image.name.clone())
.insert_str("file", image.file.clone())
});
}
builder
// ^~~~~ Can now return it
})
.build();
let _ = template.render_data(&mut io::stdout(), &data);
}
fn template<'a>() -> &'a str {
"
<ul>
{{#images}}
<li>
{{name}}
</li>
{{/images}}
</ul>
"
}
fn load_images() -> Vec<Image> {
let mut images = Vec::new();
images.push(Image::new("Picture 1", "picture-1.png"));
images.push(Image::new("Picture 2", "picture-2.png"));
images.push(Image::new("Picture 3", "picture-3.png"));
images
}
with_struct.rs:
use std::io;
use mustache;
#[deriving(Encodable)]
struct Image {
name: String,
file: String
}
#[deriving(Encodable)]
struct TemplateData<'a> {
images: &'a Vec<Image>
}
impl Image {
fn new(name: &str, file: &str) -> Image {
Image {
name: String::from_str(name),
file: String::from_str(file)
}
}
}
pub fn go() {
let images = load_images();
let template = mustache::compile_str(template());
let data = TemplateData {
images: &images
};
let _ = template.render(&mut io::stdout(), &data);
}
fn template<'a>() -> &'a str {
"
<ul>
{{#images}}
<li>
{{name}}
</li>
{{/images}}
</ul>
"
}
fn load_images() -> Vec<Image> {
let mut images = Vec::new();
images.push(Image::new("Picture 1", "picture-1.png"));
images.push(Image::new("Picture 2", "picture-2.png"));
images.push(Image::new("Picture 3", "picture-3.png"));
images
}
Ollie!
You need to remove the semicolon after last insert_str (Rust discards that line, and don't use as return value, if you put semicolon in the end).

Resources