Repository: glium/glium (language: rust)

Issue:
AsUniformType lifetime issue
I implement own uniform type like this:

``` rust
extern crate glium;

use glium::texture::Texture2d;
use glium::uniforms::{AsUniformValue, Uniforms};
use std::rc::Rc;


pub struct Foobar {
    pub texture: Rc<Texture2d>,
}

impl Uniforms for DefaultUniforms {
    fn visit_values<'a, F>(&'a self, mut f: F)
        where F: FnMut(&str, UniformValue<'a>)
    {
        f("tex", self.texture.as_ref().as_uniform_value());
    }
}
```

Encountered a lifetime issue, because creat texuture uniform value

``` rust
impl<'a> AsUniformValue for &'a Texture2d
```

Need `&'a Texture`, texture in `Rc` can't meet the lifetime requirements.

but replace `.as_uniform_value()` with direct construction:

``` rust
f("tex", UniformValue::Texture2d(&*self.texture, None));
```

Is compile success, because this is `&'a Texture` **into** `UniformValue<'a>`. https://github.com/tomaka/glium/blob/master/macros/src/uniforms.rs#L39

Make AsUniformValue::as_uniform_value() take self by value instead of reference
Taking self by reference makes this API unergonomic due to lifetime issues.



Discussion / hints:
Can fix by this way:

``` rust
extern crate glium;

use glium::texture::Texture2d;
use glium::uniforms::{AsUniformValue, Uniforms, UniformValue};
use std::rc::Rc;


#[derive(Clone)]
pub struct Tex(Rc<Texture2d>);


impl AsUniformValue for Tex {
    fn as_uniform_value(&self) -> UniformValue {
        UniformValue::Texture2d(&*self.0, None)
    }
}


pub struct Foobar {
    pub texture: Tex,
}

impl Uniforms for Foobar {
    fn visit_values<'a, F>(&'a self, mut f: F)
        where F: FnMut(&str, UniformValue<'a>)
    {
        f("tex", self.texture.as_uniform_value());
    }
}
```

but can't auto cover all type, must implement one by one. generics can't solve:

``` rust

#[derive(Clone)]
pub struct Tex<T: Texture>(Rc<T>);

impl<T: Texutre> AsUniformValue for Tex<T> {
    fn as_uniform_value(&self) -> UniformValue {
        UniformValue::?????(&*self.0, None)
    }
}
```



Fix patch:
diff --git a/build/textures.rs b/build/textures.rs
index bd684dfa8a..bd824c5007 100644
--- a/build/textures.rs
+++ b/build/textures.rs
@@ -425,6 +425,13 @@ fn build_texture<W: Write>(dest: &mut W, ty: TextureType, dimensions: TextureDim
                                 }}
                             }}
 
+                            impl AsUniformValue for {myname} {{
+                                #[inline]
+                                fn as_uniform_value(&self) -> UniformValue {{
+                                    UniformValue::{myname}(self, None)
+                                }}
+                            }}
+
                             impl<'a> AsUniformValue for Sampler<'a, {myname}> {{
                                 #[inline]
                                 fn as_uniform_value(&self) -> UniformValue {{


Test patch:
diff --git a/tests/texture_creation.rs b/tests/texture_creation.rs
index 8d8318153d..0c1ea45390 100644
--- a/tests/texture_creation.rs
+++ b/tests/texture_creation.rs
@@ -86,6 +86,29 @@ fn texture_2d_creation() {
     display.assert_no_error(None);
 }
 
+#[test]
+fn texture_2d_as_uniform_value_lifetime() {
+    let display = support::build_display();
+
+    let texture = glium::texture::Texture2d::new(&display, vec![
+        vec![(0, 0, 0, 0), (0, 0, 0, 0)],
+        vec![(0, 0, 0, 0), (0, 0, 0, 0)],
+        vec![(0, 0, 0, 0), (0, 0, 0, 0u8)],
+    ]).unwrap();
+
+    // A function that takes texture reference should be able to return UniformValue (with lifetime
+    // inherited from the reference).
+    fn get_uniforms(texture: &glium::texture::Texture2d) -> glium::uniforms::UniformValue {
+        use glium::uniforms::AsUniformValue;
+        texture.as_uniform_value()
+    }
+
+    let uniforms = get_uniforms(&texture);
+    assert!(matches!(uniforms, glium::uniforms::UniformValue::Texture2d(..)));
+
+    display.assert_no_error(None);
+}
+
 #[test]
 fn empty_texture2d_u8u8u8u8() {
     let display = support::build_display();