TIL - Implementing Encoder for NifStructs

I am currently using Rustler, a tool that allows for Elixir to interact with the Rust ecosystem. As a newcomer to Rust, working on Rust-Elixir crossover libraries helps me understand its quirks.

Today, I was trying to use a SQL parser in Rust and convert the results to Elixir terms. Rustler’s NifStructs feature made this process convenient. However, I encountered an issue with a data structure defined as follows:

#[derive(NifStruct)]
#[module = "SqlParser.Select"]
pub struct Select {
    pub selection: Option<Expr>
}

The issue arose when I encountered this enum:

pub enum Expr {
    BinaryOp {
        left: Box<Expr>,
        op: BinaryOperator,
        right: Box<Expr>,
    }
}

Because of the Box<Expr>, this becomes a recursive data structure. To encode this with Rustler, I needed to implement the Encoder trait for Box<Expr>.

impl Encoder for Box<Expr> {
    fn encode<'a>(&self, env: Env<'a>) -> Term<'a>  {
        let data =&** self;
        data.encode(env)
    }
}

However, this caused a chain reaction. The Select struct above has a Decoder trait implemented for it, and it expects Expr to also implement that trait to decode. At first, I implemented the Decoder trait for Expr, but since I only need to use the parser one-way (from SQL through Rust to Elixir) and not vice-versa, this was not necessary.

I had to do a bit of digging but found that I could use:

#[derive(NifStruct)]
#[rustler(encode)]
#[module = "SqlParser.Select"]

and the Select struct would never implement the Decoder trait, resulting in that the Expr also did not need to implement it.

So annotate the code with #[rustler(encode)] or #[rustler(decode)] if you only need one-way encoding/decoding in Rustler.