Yet another Ownership shit in Rust

Yesterday I'm dealing with a Rust pitfalls like below:

pub struct IBStream<'a> {
    qp: Arc<ibverbs::QueuePair<'a>>,
    cq: Arc<ibverbs::CompletionQueue<'a>>,
    mr: ibverbs::MemoryRegion<RdmaPrimitive>,
    pd: Arc<ibverbs::ProtectionDomain<'a>>,
    ctx: Arc<ibverbs::Context>,
}

My initiative is to make the IBStream initial in parallel. As for implementation of ctx is an unsafe code to consume CompletionQueue and cq, mr and pd have different lifetimes, so on initiate the struct, we couldn't make sure ctx's lifetime is long lived than IBStream. We couldn't write the could as below:

pub fn new<'b, A: ToSocketAddrs>(addr: A) -> Result<IBStream<'b>, IBError> {
        let ctx = Self::setup_ctx()?;
        let ctxr: & _ = &ctx;
        let cq = Self::setup_cq(ctxr)?;
        let pd = Self::setup_pd(&ctx.clone())?;
        let qp = Self::setup_qp(&cq.clone(), &pd.clone(), &ctx.clone())?;

        let mr = pd.allocate::<RdmaPrimitive>(2).unwrap();
        Ok(IBStream {
            qp,
            cq,
            mr,
            pd,
            ctx,
        })
    }


The library function specify such lifetime to let the user have to take care of ctx and cq's lifetime, which has some senses. But these thinking of lifetime is too tedious for fast deployment.

How to solve the problem? As Jon put, there's library called ouroboros that the data in the struct has the same lifetime with the outer struct, that they are created and destroyed at the same time.

#[ouroboros::self_referencing]
pub struct ClientSideConnection<'connection> {
    cq: CompletionQueue<'connection>,
    pd: &'connection ProtectionDomain<'connection>,
    #[borrows(cq, pd)]
    #[covariant]
    qp: QueuePair<'this>,
}

When using the struct, if we have to specify the static in one function.

let client = client as *const BadfsServiceClient;
// this is safe because we move client into closure, then execute the closure before function returns
let client:&'static BadfsServiceClient = unsafe{client.as_ref().unwrap()};

Another problem, if I want to specify a lifetime inside a function but the borrow checker think it's not, we could cheat it with the same trick.

All in all, borrow checker is easy to cheat.