How to register custom builtin functions?
iwinux opened this issue · 3 comments
I've defined a function like this (crate version 0.5.0-pre94
):
use jrsonnet_evaluator::function::builtin;
#[builtin]
fn timestamp() -> String {
use std::time::{SystemTime, UNIX_EPOCH};
let ts = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
ts.as_secs_f64().to_string()
}
However, when I try to register it into jrsonnet_stdlib::ContextInitializer
, I get all kinds of errors:
ctx.add_native("name".into(), timestamp)
-> "jrsonnet_evaluator::function::builtin::Builtin
is not implemented for fn item..."ctx.add_native("name".into(), timestamp::INST)
-> the samectx.add_native("name".into(), Into::<impl Builtin>::into(timestamp::INST))
-> "impl Trait
only allowed in function and inherent method return types"
From the source code of the builtin
macro, I can be sure that the Builtin
trait has already been implemented. Yet add_native
keeps complaining about type mismatch.
Please enlighten me how should this be done 😿
ctx.add_native("name".into(), timestamp {})
is the correct code here, let me explain:
#[builtin]
macros generates struct, with the same name as the function, so in case of ctx.add_native("name".into(), timestamp)
it complains because you have given it a function, not a struct.
The generated code is roughly this:
struct timestamp {}
impl timestamp {
pub const INST: &'static dyn StaticBuiltin = &#name {};
}
So ctx.add_native("name".into(), timestamp::INST)
will fail with another issue, because there is no impl Builtin for &'static dyn StaticBuiltin
due to rust limitations.
The only possible way here is to have a dynamic builtin, using struct initialization syntax.
This is an ergonomic problem, which I did not considered before, because I mostly use custom globals instead of registering std.native
functions:
https://github.com/UniqueNetwork/chainql/blob/649bf8a7885e713c14638834b051978e5a7d2275/crates/chainql-core/src/lib.rs#L1463
Wow! That's so obvious in hindsight. How could I miss it 🤣 . Thank you for explanation.
I have improved ergonomics of many methods in the master
branch, now
ctx.add_native("timestamp", timestamp::INST)
// ^ .into() is no longer needed too
Will just work.