rustjnienvraw-pointer

Casting a borrowed reference with a lifetime to a raw pointer in Rust


I am new to rust and am trying to wrap my head around lifetimes. Please consider the following code:

use jni::JNIEnv;

pub struct CameraAppEngine<'a> {
    _env: &'a JNIEnv<'a>,
    _width: i32,
    _height: i32
}

impl<'a> CameraAppEngine<'a> {
    pub fn new(_env: &'a JNIEnv<'a>, _width: i32, _height: i32) -> CameraAppEngine {
        CameraAppEngine { _env, _width, _height }
    }

    pub fn env(&'a self) -> JNIEnv<'a> {
        JNIEnv::from_raw(self._env).unwrap() // error!
    }
}

The JNIEnv::from_raw method has a type signature of from_raw(ptr: *mut JNIEnv) -> Result<Self>, so this results in the compile error:

|         JNIEnv::from_raw(self._env).unwrap()
|                          ^^^^^^^^^ types differ in mutability
|
= note: expected raw pointer `*mut *const jni::sys::JNINativeInterface_`
                found reference `&'a jni::JNIEnv<'a>`

I then tried JNIEnv::from_raw(self._env as *mut JNIEnv<'a>).unwrap(), but this results in:

|         JNIEnv::from_raw(self._env as *mut JNIEnv<'a>).unwrap() // error!
|                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected *-ptr, found struct `jni::JNIEnv`
|
= note: expected raw pointer `*mut *const jni::sys::JNINativeInterface_`
            found raw pointer `*mut jni::JNIEnv<'a>`

error[E0606]: casting `&'a jni::JNIEnv<'a>` as `*mut jni::JNIEnv<'a>` is invalid
--> native_app/src/camera_engine.rs:16:26
|
|         JNIEnv::from_raw(self._env as *mut JNIEnv<'a>).unwrap() // error!
|                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

How do I get a valid JNIEnv out of the reference in the struct?

Cheers and thank you for your time!

Update

Here is a less contrived way to demonstrate the prolem.

pub fn create_camera_session(&'a mut self, surface: jobject) {
    // error!
    let window = ffi::ANativeWindow_fromSurface(self._env as *mut JNIEnv<'a>, surface);
}

This results in:

error[E0606]: casting `&'a jni::JNIEnv<'a>` as `*mut jni::JNIEnv<'a>` is invalid

The type signature of ANativeWindow_fromSurface is ANativeWindow_fromSurface(env: *mut JNIEnv, surface: jobject) -> *mut ANativeWindow.


Solution

  • There are two types named JNIEnv in the jni crate:

    1. jni::sys::JNIEnv: This is a type alias: type JNIEnv = *const JNINativeInterface_;
    2. jni::JNIEnv: This is a safe wrapper around jni::sys::JNIEnv.

    You cannot simply use as to cast between the two, because they are unrelated types. In fact, in your env() method, you can just clone self._env. Furthermore, jni::JNIEnv is just a wrapper for a pointer, and cloning is cheap (it's not a deep copy), so you can store it by value rather by reference in self._env.

    jni::JNIEnv exposes methods to convert between the two types. jni::JNIEnv::from_raw goes from jni::sys::JNIEnv to jni::JNIEnv, and jni::JNIEnv::get_native_interface goes the other way.