elixir-explorer / explorer

Series (one-dimensional) and dataframes (two-dimensional) for fast and elegant data exploration in Elixir
https://hexdocs.pm/explorer
MIT License
1.12k stars 123 forks source link

implement `message_on_gc` in Rust #931

Closed cocoa-xu closed 4 months ago

cocoa-xu commented 4 months ago

Some background on this

I'm implementing a NIF that receives a process pid and a term message. And it will return a reference representing a NIF resource. Once the resource is GCed, it should send the term message it received earlier to the given process pid.

Issues

When implementing this message_on_gc in Rust I have serval issues/questions, and the very first one is,

if I want to hold a value of a NIF term (passed from Elixir, assuming it can be any valid Erlang terms) in LocalMessage, it will have a lifetime 'a, thus LocalMessage should be:

pub struct LocalMessage<'a> {
    pub pid: LocalPid,
    pub term: Term<'a>,
}

and all subsequent struct that contains a LocalMessage would also have lifetime that is at least 'a. Therefore, if I want to have an ExLocalMessageRef that holds a LocalMessage, it should be:

pub struct ExLocalMessageRef<'a>(pub LocalMessage<'a>);

impl<'a> ExLocalMessageRef<'a> {
    pub fn new(m: LocalMessage<'a>) -> Self {
        Self(m)
    }
}

As a result, this requires me to mark the on_load function with lifetime 'a so that I can use rustler::resource! for ExLocalMessageRef<'a>

fn on_load<'a>(env: Env, _info: Term) -> bool {
    rustler::resource!(ExDataFrameRef, env);
    rustler::resource!(ExExprRef, env);
    rustler::resource!(ExLazyFrameRef, env);
    rustler::resource!(ExSeriesRef, env);
    rustler::resource!(ExLocalMessageRef<'a>, env);
    true
}

But the problem is, in rustler::resource!, the resource type is declared as static, which requires lifetime 'a to outlive 'static.

static mut STRUCT_TYPE: Option<$crate::resource::ResourceType<$struct_name>> = None;

I'm not sure if I should use lifetime 'static for LocalMessage and ExLocalMessageRef because it doesn't look quite right to me. Plus using 'static is invalid on structs as it is a reserved lifetime name.

I don't quite think that I'm the right track for this... I would greatly appreciate any suggestions anyone may have for me.