Can't make global from complex struct

So I need to be able to access my renderer from anywhere but I can not make a global variable from Renderer struct.
Its a struct build off of wgpu so its values are bit complex and I can not seem to find a way to have "empty" values for it.

In C I would just have a global / static variable that has nullptr and just assign it in main. Then I would be able to just use it anywhere. I also looked at singleton pattern for Rust but it requires proper default for struct as well.

Edit: I also do not like the idea I have to use unsafe for global variable in this use case.

Here is Renderer struct

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

Here I try to make a default value for it to start off as but my struct has values that I can't seem to find way to start off as n


impl Renderer
{
    pub fn empty() -> Self
    {
        Self
        {
            surface::default, //default does not exist
            None, // None does not work
            None,
            None
        }
    }
}

Here is main code

use framework_app_winit::App;
use framework_renderer_sprite_2d_wgpu::Renderer;

static mut RENDERER : Renderer = Renderer::empty();

fn main() 
{
   //Create app
   let _app = App::new()
      .set_window_title("Game framework")
      .set_window_maximized(false)
      .add_on_window_event_resized(on_window_event_resized)
      .add_start_system(start)
      .add_update_system(update)
      .add_update_system(render);

   //Create renderer (pass in window to create render surface from window raw handel)
   unsafe
   {
      RENDERER = Renderer::new_from_winit(&_app.get_window()).0;
   }
   
   //Run app
   _app.run();
}

fn on_window_event_resized(width : u32, height : u32)
{
   unsafe
   {
      RENDERER.resize(width, height);
   }
}

fn start()
{
}

fn update()
{
}

fn render()
{
   unsafe
   {
      RENDERER.begin_draw([0.1,0.2,0.3]);
   }
}

I think you should be able to accomplish this with lazy_static.

Rust needs to have a guarantee that all global variables are valid at all times, even before main is run. That's because it can't guarantee that you won't run anything else before initializing them, or even when you start initializing that the initialization code won't call any other function that observes them in uninitialized state. There's no such clever code-flow based analysis, only strict global rules.

once_cell::Lazy is another solution for lazy init of globals.

Note that you've used C syntax for your struct literal. Rust's syntax always needs field names.

2 Likes

Haven’t been once_cell contents moved to core::cell? once_cell::Lazy is core::cell::LazyCell

UPD: Sorry, forgot that not everyone uses nightly compiler.

why don't you use Option for the fields :

pub struct Renderer
{
    surface: Option<Surface>,
    device: Option<Device>,
    queue: Option<Queue>,
    surface_config: Option<SurfaceConfiguration>
}