rune
rune copied to clipboard
Can't construct struct with named field
Hi, I can't construct struct like this:
let action = SendAction {
seq: 1,
target_id: "123",
headers: [],
body_bytes: Bytes::new(),
wait_strategy: RuneWaitStrategy::Ignore
};
its will cause an error:
missing runtime information for variant with hash 0xe49bb8eb2c9a12e7 (at inst 40)
I know I must be doing something wrong, but I don't know how to debug and fix it.
Here is my rune code
#[cfg(test)]
mod test {
// rune 0.11.0 from git master
// rune-modules 0.11.0
// rust version: 1.61.0
// windows
use std::sync::Arc;
use std::time::Duration;
use rune::runtime::{SyncFunction, VmError};
use rune::termcolor::{ColorChoice, StandardStream};
use rune::{Context, ContextError, Diagnostics, FromValue, Module, Vm};
#[derive(Debug, Clone, rune::Any)]
pub enum RuneWaitStrategy {
#[rune(constructor)]
Ignore,
#[rune(constructor)]
Must(#[rune(get)] Dur),
#[rune(constructor)]
AsyncOnError,
#[rune(constructor)]
AsyncAlways,
}
#[derive(Debug, Clone, rune::Any)]
pub struct SendAction {
#[rune(get, set)]
pub seq: u64,
#[rune(get, set)]
pub target_id: String,
#[rune(get, set)]
pub headers: Vec<(String, String)>,
#[rune(get, set)]
pub body_bytes: rune::runtime::Bytes,
#[rune(get, set)]
pub wait_strategy: RuneWaitStrategy,
}
#[derive(Debug, Clone, rune::Any)]
pub struct Dur {
pub inner: Duration,
}
fn module() -> Result<Module, ContextError> {
let mut module = Module::with_crate("m_action");
module.ty::<SendAction>()?;
module.ty::<RuneWaitStrategy>()?;
module.ty::<Dur>()?;
Ok(module)
}
#[test]
pub fn test() {
let mut sources = rune::sources! {
entry => {
use m_action::*;
use std::bytes::*;
fn next(seq, events) {
let action = SendAction{
seq: 1,
target_id: "123",
headers: [],
body_bytes: Bytes::new(),
wait_strategy: RuneWaitStrategy::Ignore
};
// but this works
//let action = SendAction::new(...)
action
}
pub fn main() {
next
}
}
};
let m = module().unwrap();
let mut context = Context::with_default_modules().unwrap();
context.install(&m).unwrap();
let runtime = Arc::new(context.runtime());
let mut diagnostics = Diagnostics::new();
let result = rune::prepare(&mut sources)
.with_context(&context)
.with_diagnostics(&mut diagnostics)
.build();
if !diagnostics.is_empty() {
let mut writer = StandardStream::stderr(ColorChoice::Always);
diagnostics.emit(&mut writer, &sources).unwrap();
}
let unit = result.unwrap();
let mut vm = Vm::new(runtime, Arc::new(unit));
let controller_f = SyncFunction::from_value(vm.call(&["main"], ()).unwrap()).unwrap();
// error here: MissingRtti hash: xxx
let mut action: SendAction = controller_f.call((1, 2)).unwarp();
}
}
Thanks for the report!
So I think the issue lies in try_lookup_meta. It forgets to add the meta to the UnitBuilder, so ultimately the compiled Unit is missing the run-time type information (RTTI) when the VM tries to construct the object later on.
All that's needed is to include that extra line, like we do in the index_meta call:
self.unit.insert_meta(location.as_spanned(), &meta, self.pool, self.inner)?;
self.insert_meta(meta.clone()).with_span(location.as_spanned())?;
Then something like this will work fine:
pub fn main() {
let external = External {
first: 1,
second: "two",
};
external
}
But this fails if you want to extract the value from the VM:
let output = vm.call(["main"], ())?;
let output: External = rune::from_value(output)?;
println!("{:?}", output);
Error: Expected `Any` type, but found `External`
Because the from_value implementation is expecting a Value::Any, when it's actually a Value::Struct. That means the VM is actually treating the External Rust struct as a Rune struct, just reusing the field names. You can debug the Value and see the correct result, or coerce it into a Shared<Struct> and interact with it as an object using .get("first").
To get an actual External type from the VM, I think we'd need to push an instance of External onto the stack as an Value::Any, which would require associating a constructor function with the type like enum variants have now. See my draft PR (#589) for an attempt at that.