Some input types cannot be converted to Rust cleanly (may cause errors), and may need special handling. For example, converting VCL_STRING to &str could fail because C string may contain invalid UTF8 chars. We do NOT want to panic when a user function is being called, so we need to modify macro-generated code.
To handle this properly, we must use TryFrom instead of From trait for cases like TryFrom<VCL_STRING> for &str, and if it fails, log the error and return default value. We consolidate error handling because multiple thing can fail. In order to use the ? quick return, we need to wrap it in another nested function.
Note that Default is not implemented for every return type (e.g. some raw VCL_* types), so this code would fail to compile if the user function returns it. Thus, we must either generate simpler code if no error handling is required, or ensure every return type implements Default.
// user function
pub fn user_fn(foo: &str, bar: &str) -> Result<i64, VclError> {}
// proposed generated code
unsafe extern "C" fn vmod_c_user_fn(
ctx: *mut vrt_ctx,
foo: VCL_STRING,
bar: VCL_STRING,
) -> VCL_INT {
// context is needed both inside the lambda and to handle errors
let mut ctx = Ctx::from_ptr(ctx);
// Call user function using a lambda
// this allows early returns if any of the try_from fail
// this also keeps all error handling consistent with VclError
let call_user_fn = || -> Result<i64, VclError> {
let var0: &str = foo.try_into()?;
let var1: &str = bar.try_into()?;
// if user_fn does not return Result, remove the "?"
// we should not return the result directly because we may need error type coercion
Ok(super::user_fn(var0, var1)?)
};
call_user_fn()
// this step can be skipped for basic types
.and_then(|res| res.into_vcl(&mut ctx.ws))
.unwrap_or_else(|e| {
ctx.fail(e);
Default::default()
})
}
Some input types cannot be converted to Rust cleanly (may cause errors), and may need special handling. For example, converting
VCL_STRING
to&str
could fail because C string may contain invalid UTF8 chars. We do NOT want to panic when a user function is being called, so we need to modify macro-generated code.To handle this properly, we must use
TryFrom
instead ofFrom
trait for cases likeTryFrom<VCL_STRING> for &str
, and if it fails, log the error and return default value. We consolidate error handling because multiple thing can fail. In order to use the?
quick return, we need to wrap it in another nested function.Note that
Default
is not implemented for every return type (e.g. some rawVCL_*
types), so this code would fail to compile if the user function returns it. Thus, we must either generate simpler code if no error handling is required, or ensure every return type implements Default.