fn visitor_send_and_wait(bridge: &{{ struct_name }}, callback_name: &str, args_json: String) -> Option<String> {
    let (tx, rx) = std::sync::mpsc::sync_channel::<Option<String>>(1);
    let ref_id = VISITOR_REPLY_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
    VISITOR_CHANNELS.lock().unwrap().insert(ref_id, tx);
    let pid = bridge.caller_pid;
    let cb_name = callback_name.to_string();
    let mut msg_env = rustler::OwnedEnv::new();
    let _ = msg_env.send_and_clear(&pid, |env| {
        let tag = rustler::types::atom::Atom::from_str(env, "visitor_callback").unwrap().to_term(env);
        let ref_term = ref_id.encode(env);
        let name_term = rustler::types::atom::Atom::from_str(env, &cb_name).unwrap().to_term(env);
        let args_term = args_json.encode(env);
        rustler::types::tuple::make_tuple(env, &[tag, ref_term, name_term, args_term])
    });
    let result = rx.recv().ok().flatten();
    VISITOR_CHANNELS.lock().unwrap().remove(&ref_id);
    result
}
