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.
Top comments (0)