Lifetime of rust references and structs with raw pointer fields


#1

I have a large struct from a C API that contains raw pointer fields. Defaults are null but i would like to implement methods that take rust references and set the fields. The references should outlive the struct. I tried to use explicit lifetimes but without extending the struct i cannot get the compiler to guarantee that the references outlive the struct. Here’s a condensed example:

pub struct Struct<'a> {
    pub b: *const u8,
    // pub c: &'a ()
}

impl <'a> Struct<'a> {
    pub fn set(&mut self, arg: &'a [u8]) {
        self.b = arg.as_ptr();
    }
}

fn main() {
    let mut s = Struct {
        b: std::ptr::null(),
        // c: &(),
    };
    {
        let a = [1,2,3];
        s.set(&a);
    }
    println!("{:?}", s.b);
}

The compiler doesn’t complain here although the referenced array goes out of scope before the struct. But If i add field ‘c’ (a reference to nothing) the compiler rightly complains about the lifetime of the reference passed to the method. Is there a way to force that without adding a field?


#2

I think [std::marker::ContravariantLifetime](file:///F:/Programs/Rust/share/doc/rust/html/std/marker/struct.ContravariantLifetime.html) is what you want. The following fails to compile due to lifetime issues:

use std::marker::ContravariantLifetime;

pub struct Struct<'a> {
    pub b: *const u8,
    _marker: ContravariantLifetime<'a>,
}

impl <'a> Struct<'a> {
    pub fn set(&mut self, arg: &'a [u8]) {
        self.b = arg.as_ptr();
    }
}

fn main() {
    let mut s = Struct {
        b: std::ptr::null(),
        _marker: ContravariantLifetime,
    };
    {
        let a = [1,2,3];
        s.set(&a);
    }
    println!("{:?}", s.b);
}

#3

Yes that seems to work and the size of the struct does not increase. I need to read more about those lifetime markers because i don’t fully understand them yet.


#4

Perhaps it’s not a good time to start reading about the variance markers, as they are likely to be redesigned soon: https://github.com/rust-lang/rfcs/pull/738