#Trying to return a struct with fields that reference one of the fields (Inkwell)

7 messages · Page 1 of 1 (latest)

empty zephyr
#

Hi, I'm new to Rust and trying to use Inkwell (LLVM safe wrapper) . I'm trying to make a struct for code emitting that contains multiple Inkwell objects: context, module, builder, execution_engine. Notably, the latter three contain a reference to the first and I want to make a constructor that returns them together.

The problem is, I'm trying to move context into the emitter struct, after creating references to it. I wonder what is the idiomatic rust solution to this.

I want to avoid:

  • using Rc
  • using options to half initialize the struct first
  • using hacks in general
  • cloning anything

here is the code:

use inkwell::builder::Builder;
use inkwell::context::Context;
use inkwell::execution_engine::{ExecutionEngine, JitFunction};
use inkwell::module::Module;
use inkwell::OptimizationLevel;

use std::error::Error;

struct Emitter<'ctx> {
    context: Box<Context>,
    module: Module<'ctx>,
    builder: Builder<'ctx>,
    execution_engine: ExecutionEngine<'ctx>,
}

impl<'ctx> Emitter<'ctx> {
    pub fn emit(&mut self) {}
}

pub fn new_emitter<'a>() -> Option<Emitter<'a>> {
    let context = Box::new(Context::create());
    let module = context.create_module("main");
    let builder = context.create_builder();
    let execution_engine = module
        .create_jit_execution_engine(OptimizationLevel::None)
        .unwrap();
    Some(Emitter {
        context,
        module,
        builder,
        execution_engine,
    })
}

Help is much appreciated ^^

#

I understand why it doesn't compile btw, just curious how to write it in an idiomatic way without using hacks

daring flicker
#

It's impossible to express this “self-referential” data structure as a plain struct and, unfortunately, neither is there a really “idiomatic” alternative other than “stop trying; let the Context be owned by a parent stack frame”

#

The options are:

  1. don't try to package borrows and owned values like this
  2. patch the library / use a different library that uses Rcs for this type of relationship instead of &s
  3. use a self-reference tool like https://docs.rs/ouroboros
  4. use an async block to own all the things; this is the one kind of officially supported self-reference (because it can do all the things a regular function can do, but is also a data structure), but you are then limited to interacting with the borrowing values (module etc) in an “actor pattern” fashion (send it messages, run the async block till it sends a response)
#

In my personal opinion, because Rust doesn’t support this pattern directly, libraries that only let you use borrows to work with major objects like Context are flawed libraries that should be fixed (option 2). I understand why they do it (it's free at run time, and it maps directly on to C-idiomatic “documentation says do not destroy this until after you destroy those”), but they shouldn’t.

#

And Rust should support this pattern, but there's no clear path to doing that any time soon, so we have to work with 2, 3, or 4

empty zephyr
#

thanks for the explanation!