/// Run conversion using a callback-based visitor.
///
/// Returns a heap-allocated result on success, or null on failure.
/// Check `{{ prefix }}_last_error_code` / `{{ prefix }}_last_error_context` for error details.
/// The returned pointer must be freed with the matching result free function.
///
/// # Safety
///
/// `html` must be a valid, non-null, null-terminated UTF-8 string.
/// `options` must be a valid pointer or null.
/// `visitor` must have been created with `{{ prefix }}_visitor_create`, or be null.
/// Returned pointer must be freed with the matching result free function.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn {{ with_visitor_fn_name }}(
{% for param in params %}
{{ param }},
{% endfor %}
visitor: AlefHandle,
) -> AlefHandle {
catch_ffi_panic(0, || {
clear_last_error();
{{ param_conversions }} struct VisitorRef(AlefHandle);
impl std::fmt::Debug for VisitorRef {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("VisitorRef").finish_non_exhaustive()
}
}
impl {{ trait_path }} for VisitorRef {
{{ visitor_ref_methods }} }
let visitor_handle: Option<std::sync::Arc<std::sync::Mutex<dyn {{ trait_path }} + Send>>> = if visitor == 0 {
None
} else {
Some(std::sync::Arc::new(std::sync::Mutex::new(VisitorRef(visitor))))
};
{{ call }}
Ok(result) => match insert_handle(result) {
Ok(handle) => handle,
Err(error) => { set_handle_error(&error); 0 }
},
Err(e) => {
set_last_error(2, &e.to_string());
0
}
}
})
}