Giving struct field as parameter to library function?


#1

In my project I use sdl2 binding. I have a System struct that has a vector of Windows.
In paint() method of System struct I have code like this:

pub fn paint(renderer: &mut Renderer) {
        unsafe {
            let system = &mut *system_ptr; // The system is like singletone
            let mut new_windows: Vec<Win> = Vec::new();
            while system.windows.len() > 0 {
                let mut win: Win = system.windows.remove(0 as usize);
                if win.need_paint() {
                    win = win.paint(renderer);
                }
                new_windows.push(win);
            }
            system.windows.append(&mut new_windows);
        }
    }

The structure was born of a struggle with borrow checker, as sdl2 bindings need whole data as params, not refs.
My windows are like this:

pub struct Win {
    id: u32,
    app_id: u32,
    title: String,
    win_table: String,
    top: i32,
    left: i32,
    width: u32,
    height: u32,
    msg_queue: Queue<Msg>,
    texture: Option<Texture>,
}

And the paint:

    pub fn paint(mut self, renderer: &mut Renderer) -> Win {
        // Creating own texture buffer if needed
        match self.texture {
            Some(..) => {},
            None => {
                match renderer.create_texture_target(PixelFormatEnum::RGBA8888, (self.width, self.height)) {
                    Ok(texture) => { self.texture = Some(texture); },
                    Err(msg) => panic!(msg),
                }
            }
        }
        // Set target to the texture
        {
            let mut target = renderer.render_target().unwrap();
            target.set(self.texture.unwrap());
        }
        // Draw our window
        renderer.set_draw_color(sdl2::pixels::Color::RGB(0xd4, 0xd0, 0xc8));
        let rect = Rect::new(0, 0, self.width, self.height).unwrap().unwrap();
        renderer.fill_rect(rect);
        
        // Return renderer target to the screen
        {
            let mut target = renderer.render_target().unwrap();
            match target.reset() {
                Ok(texture) => { self.texture = texture; },
                Err(msg) => { self.texture = None; },
            }
        }
        
        let dst_rect = Rect::new_unwrap(self.left, self.top, self.width, self.height);
        renderer.copy(&self.get_texture().unwrap(), None, Some(dst_rect));
        
        self
    }

But I have an error like this:

Compiling Test v0.0.1 (file:///D:/PROJECTS/Rust/Test)
src\syslib\win.rs:97:9: 97:13 error: use of moved value: self [E0382]
src\syslib\win.rs:97 self
^~~~
src\syslib\win.rs:97:9: 97:13 help: run rustc --explain E0382 to see a detailed explanation
src\syslib\win.rs:95:24: 95:28 note: self moved here because it has type syslib::win::Win, which is non-copyable
src\syslib\win.rs:95 renderer.copy(&self.get_texture().unwrap(), None, Some(dst_rect));
^~~~

As I see, I must give the self.texture to render.copy(), but it doesn’t want a ref, it wants my texture.
How can I circumvent this?


#2

Without the get_texture function we can only guess. But most likely you could write self.texture.by_ref().unwrap() to obtain an Option<&Texture> which points to the self.texture object. The documentation on by_ref is very helpful to understand why it’s necessary sometimes.


#3

The problem is that Texture in rust-sdl2 doesn’t have that method:

error: no method named by_ref found for type sdl2::render::Texture in the current scope


#4

your texture struct member is an Option<Texture> and the by_ref function exists on Option<T>


#5

error: no method named by_ref found for type core::option::Option<sdl2::render::Texture> in the current scope

The code is like this:

pub fn get_texture(self) -> Option<Texture> {
    self.texture.by_ref()
}

May be I’m missing something? Should I use something?


#6

The correct method in question is as_ref.

https://doc.rust-lang.org/core/option/enum.Option.html#method.as_ref


#7

whoops… I confused it with the Iterator function…


#8

Thanks! I think it will compile in that place.
Now it’s complaining about vector.append()…