'Neon bindings example with RefCell not working

I'm trying to figure out how to use native Rust modules in NodeJS using the Neon crate. To get started I was following an example using RefCell to make it possible to call mut functions on an object through JavaScript.

However, when I copy the example code, it doesn't compile. It says Cannot borrow immutable local variable 'person' as mutable & no method named 'set_name' found for mutable reference '&mut neon::handle::Handle<'_, neon::prelude::JsBox<std::cell::RefCell<Person>>>' in the current scope (positions given in comments in the code below)

I really need this kind of functionality in my app, because it needs some engine running in the background, controlled via JS. Any hints are appreciated.

It's about the following code (source):

type BoxedPerson = JsBox<RefCell<Person>>;

struct Person {
     name: String,
}

impl Finalize for Person {}

impl Person {
    pub fn new(name: String) -> Self {
        Person { name }
    }
 
    pub fn set_name(&mut self, name: String) {
        self.name = name;
    }
 
    pub fn greet(&self) -> String {
        format!("Hello, {}!", self.name)
    }
}
 
fn person_new(mut cx: FunctionContext) -> JsResult<BoxedPerson> {
    let name = cx.argument::<JsString>(0)?.value(&mut cx);
    let person = RefCell::new(Person::new(name));
 
    Ok(cx.boxed(person))
}
 
fn person_set_name(mut cx: FunctionContext) -> JsResult<JsUndefined> {
    let person = cx.argument::<BoxedPerson>(0)?;

    // Cannot borrow immutable local variable 'person' as mutable
    let mut person = person.borrow_mut();
    let name = cx.argument::<JsString>(1)?.value(&mut cx);
 
    // no method named `set_name` found for mutable reference 
    // `&mut neon::handle::Handle<'_, neon::prelude::JsBox<std::cell::RefCell<Person>>>` 
    // in the current scope
    person.set_name(name);
 
    Ok(cx.undefined())
}
 
fn person_greet(mut cx: FunctionContext) -> JsResult<JsString> {
    let person = cx.argument::<BoxedPerson>(0)?;
    let person = person.borrow();
    let greeting = person.greet();
 
    Ok(cx.string(greeting))
}


Solution 1:[1]

I found a way around it by doing the following:

fn person_set_name(mut cx: FunctionContext) -> JsResult<JsUndefined> {
    let person = cx.argument::<BoxedPerson>(0)?;

    let person = &*(*person);
    let mut person = person.borrow_mut();

    let name = cx.argument::<JsString>(1)?.value(&mut cx);
    person.borrow_mut().set_name(name);

    Ok(cx.undefined())
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 wouter_ensink