Help understanding why I get move error

I am going to explain what I am trying to accomplish so it can be understood why I split up my code as such.
Goal is to make a game framework in rust with its primary goal being to be very modular. Each part of the framework should be fully decoupled from the other parts. So if someone wants to use a different renderer or window handeling framework they can use the rest of the framework as is.

I have
- framework_app (handels windows
- framework_render_sprite_2d

Issue I am having is that I am getting a move error.
This happens when I call the following in the main

let _framework_renderer_sprite_2d = Renderer::new(&_app.get_window());

App.run than gets a error.

use of moved value: `_app`
value used here after moverustcE0382
main.rs(12, 60): `_app` moved due to this method call
main.rs(7, 8): move occurs because `_app` has type `framework_app::App`, which does not implement the `Copy` trait
app.rs(136, 23): this function takes ownership of the receiver `self`, which moves `_app`

I am not sure how to get around this. Any help would be appreciated.

Here is code
Here is my main function

use framework_app::*;
use framework_renderer_sprite_2d::*;

fn main() 
{
   //Create app
   let _app = App::new()
      .set_window_title("Game framework")
      .set_window_maximized(false);

   //Create renderer (pass in window to create render surface from window raw handel)
   let _framework_renderer_sprite_2d = Renderer::new(&_app.get_window());

   //Run app
   _app.run();
}

Here is app code

/*
Creates a app using winit to handel
    - window
    - loop via EventLoop
    - events
    - input
    - systems
Supports the following platforms
    - windows
    - linux via Wayland
    - mac
    - android
    - iOS
    - webAssembly
*/

/*=============================================================================
Framework app : Imports
=============================================================================*/

use tracing::{error, info, warn};
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;
use winit::{
    event::*,
    event_loop::{ControlFlow, EventLoop},
    window::{Window, WindowBuilder},
};

/*=============================================================================
Framework app : App
=============================================================================*/

pub struct App
{
    window : Window,
    event_loop : EventLoop<()>
}

impl App
{
    pub fn new() -> Self
    {
        // Tracing setup (logging)
        cfg_if::cfg_if! 
        {
            if #[cfg(target_arch = "wasm32")] 
            {
                console_error_panic_hook::set_once();
                tracing_wasm::set_as_global_default();
            } 
            else 
            {
                tracing_subscriber::fmt::init()
            }
        }

        // Create window with event loop
        let event_loop = EventLoop::new();
        let window = WindowBuilder::new().build(&event_loop).unwrap();

        // Wasm (Bind windows canvas to html div)
        #[cfg(target_arch = "wasm32")]
        {
            // Winit prevents sizing with CSS, so we have to
            // set the size manually when on web.
            use winit::dpi::PhysicalSize;
            window.set_inner_size(PhysicalSize::new(450, 400));

            use winit::platform::web::WindowExtWebSys;
            web_sys::window()
            .and_then(|win| win.document())
            .and_then(|doc| 
            {
                let dst = doc.get_element_by_id("framework_app")?;
                let canvas = web_sys::Element::from(window.canvas());
                dst.append_child(&canvas).ok()?;
                Some(())
            })
            .expect("Couldn't append canvas to div.");
        }

        
        Self
        {
            window,
            event_loop,
        }

    }

    pub fn run(self)
    {
        self.event_loop.run(move |event, _, control_flow| match event 
        {
            Event::WindowEvent 
            {
                ref event,
                window_id,
            } 
            if window_id == self.window.id() => match event
            {
                WindowEvent::CloseRequested 
                {  
                } => *control_flow = ControlFlow::Exit,
                _ => {}
            },
            _ => {}
        });
    }

    pub fn set_window_title(self, title : &str) -> Self
    {
        self.window.set_title(title);
        self
    }

    pub fn set_window_maximized(self, maximized : bool) -> Self
    {
        self.window.set_maximized(maximized);
        self
    }

    pub fn set_window_minimized(self, minimized : bool) -> Self
    {
        self.window.set_minimized(minimized);
        self
    }

    pub fn set_window_decorations(self, decorations : bool) -> Self
    {
        self.window.set_decorations(decorations);
        self
    }

    pub fn get_window(self) -> Window
    {
        self.window
    }
}

Here is renderer code

/*=============================================================================
Framework renderer sprite 2d : Renderer
=============================================================================*/

pub struct Renderer
{
    surface: wgpu::Surface,
    device: wgpu::Device,
    queue: wgpu::Queue,
    surface_config: wgpu::SurfaceConfiguration
}

impl Renderer
{
    // Creating some of the wgpu types requires async code
    pub fn new(window: &Window) -> (Self, &Window) 
    {
        let instance = wgpu::Instance::new(wgpu::Backends::all());
        let surface = unsafe { instance.create_surface(&window) };
        let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
            power_preference: wgpu::PowerPreference::default(),
            compatible_surface: Some(&surface),
            force_fallback_adapter: false,
        }))
        .unwrap();
    
        let (device, queue) = pollster::block_on(adapter.request_device(
            &wgpu::DeviceDescriptor {
                label: None,
                features: wgpu::Features::empty(),
                limits: wgpu::Limits::default(),
            },
            None, // Trace path
        ))
        .unwrap();
    
        let size = window.inner_size();
        let surface_config = wgpu::SurfaceConfiguration 
        {
            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
            format: surface.get_supported_formats(&adapter)[0],
            width: size.width,
            height: size.height,
            present_mode: wgpu::PresentMode::Fifo,
        };
        surface.configure(&device, &surface_config);

        (Self
        {
            surface,
            device,
            queue,
            surface_config
        },
        window)
    }
}

This function:

pub fn get_window(self) -> Window

Should take a reference:

pub fn get_window(&self) -> &Window

You should read the chapter of the book on methods.

In general in rust we don't really use getters. So it should just be &app.window directly.

2 Likes

Thanks.
I read that for sure.