How do you determine the lifespan in related types?

I am trying to get each implementation GraphicsContext

to return a different implementation Shader

.

pub trait Resources {
    type Shader: shader::Shader;
}

pub trait GraphicsContext {

    type Resources: Resources;

    /// Creates a shader object
    fn create_shader<'a>(&'a self, shader::Stage, source: &str)
        -> Result<<<Self as GraphicsContext>::Resources as Resources>::Shader,
                  shader::CreateError>;

    /// Creates a shader program object
    fn create_shader_program<'a>(&'a self, shaders: Vec<&shader::Shader>)
        -> Result<Box<shader::ShaderProgram + 'a>, shader::ProgramCreateError>;

    // more to come

}

      

This means that the method create_shader_program

(and other methods) knows a specific type Shader

so that they can call specific implementation methods on the shader object.

I don't want to put these methods (like setCurrent

or attach

) in a trait that all implementations should use. Not all graphics APIs use the same system: OpenGL is bind / unbind, Vulkan will be structs / given fields, DirectX is something else, etc.

First, I ask what is the correct way to structure my engine. I believe that in my framework / application code that requires these objects Shader

, I can specify a specific type based on the current type Context

.

// almost certain this doesn't compile, but should be possible in theory
// I'm trying to say:
// the type of the `shader` argument must match to the associated type
// contained within the `context`
fn do_something_with_shader(context: &GraphicsContext,
                            shader: ??**GraphicsContext::Resources::Shader**??)
                           -> Result<Foo, Bar>;

      

or perhaps:

fn do_something_with_shader<T>(context: &GraphicsContext<T>,
                               shader: ??**T::Shader**??)
    where T: GraphicsContext::Resources -> Result<Foo, Bar>;

      

Is something like this possible? Hope you can see how I understand basic generics (I come from Java), but this is driving me crazy (this is a very brave person).

If this is the right way, then there is a problem with my implementation. rustc

wants the associated type to have the specified lifetime.

wrong number of lifetime parameters: expected 1, found 0 [E0107]
opal_driver_gl/src/context.rs:23     type Shader = Shader;

      

My OpenGLShader

struct is actually of type OpenGLShader<'a>

, so the error makes sense. My question is where can I get my whole life out of this bunch of code:

struct OpenGLResources;

impl Resources for OpenGLResources {
    type Shader = OpenGLShader;
}

impl GraphicsContext for OpenGLGraphicsContext {

    type Resources = Resources;

    /// Creates a shader object
    fn create_shader<'a>(&'a self, stage: core_shader::Stage, source: &str)
        -> Result<<<Self as GraphicsContext>::Resources as Resources>::Shader,
                  core_shader::CreateError> {
       // impl goes here
    }

}

      

I tried to bind the lifetime to OpenGLResources

and OpenGLGraphicsContext

, which solved the error, but then said error: parameter 'a is never used

.

So, secondly, I am asking how to include this lifetime in my bound type .

Thanks a lot if you can take a look at this. I feel like something like this should be checked at compile time, but I'm pretty new to Rust so I just can't figure out how to implement it.

+3


source to share


1 answer


I ended up switching to generics, which ensured a successful implementation.

Given Resources<'a>

, I can define GraphicsContext

like this:

trait GraphicsContext<'a, R: Resources<'a>>

      

For Shader<'a>

and ShaderProgram<'a>

structures insideResources



it takes 2 'a

lifetimes above.

Then an OpenGL implementation can be implemented. Please note what has Resources

been changed to OpenGLResources

.

                             // replaced here
impl<'a> GraphicsContext<'a, OpenGLResources<'a>> for OpenGLGraphicsContext<'a> {

    fn create_shader(&'a self, ty: Type, source: &str) -> Result<Shader<'a>, ShaderCreationError> {
        // do something
    }

}

      

0


source







All Articles