Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899#![allow(clippy::unwrap_used, clippy::expect_used)]
//! A fake Erlang node that serves the `$gen_call` requests our RPC chains make.//!//! Test-only: it answers `rex` from a handler the test supplies, so a chain of//! calls can be exercised without a running BEAM.
use crate::connection::TestPeer;use eetf::{Pid, Term, Tuple};use erl_dist::message::Message;use std::sync::{Arc, Mutex};
/// Records the MFAs a fake node was asked to run, in order.#[derive(Clone, Default)]pub(crate) struct CallLog(Arc<Mutex<Vec<(String, String)>>>);
impl CallLog { pub(crate) fn mfas(&self) -> Vec<(String, String)> { self.0.lock().unwrap().clone() }}
/// Serves `$gen_call` requests to `rex` from `handler` until the/// connection closes.pub(crate) fn spawn( peer: TestPeer, handler: impl Fn(&str, &str, &[Term]) -> Term + Send + 'static,) -> CallLog { let log = CallLog::default(); let recorded = log.clone();
tokio::spawn(async move { let (mut peer_tx, mut peer_rx) = peer;
while let Ok(message) = peer_rx.recv().await { let Message::RegSend(reg_send) = message else { continue; }; let Some((reply_to, tag, module, function, args)) = decode_gen_call(reg_send.message) else { continue; };
recorded .0 .lock() .unwrap() .push((module.clone(), function.clone()));
let result = handler(&module, &function, &args); let reply = Message::send(reply_to, Term::from(Tuple::from(vec![tag, result]))); if peer_tx.send(reply).await.is_err() { break; } } });
log}
/// Unpacks `{'$gen_call', {Pid, Tag}, {call, M, F, Args, GL}}`.fn decode_gen_call(term: Term) -> Option<(Pid, Term, String, String, Vec<Term>)> { let Term::Tuple(outer) = term else { return None; }; let [_, from, call] = outer.elements.as_slice() else { return None; };
let Term::Tuple(from) = from else { return None; }; let [Term::Pid(reply_to), tag] = from.elements.as_slice() else { return None; };
let Term::Tuple(call) = call else { return None; }; let [ _, Term::Atom(module), Term::Atom(function), Term::List(args), _, ] = call.elements.as_slice() else { return None; };
Some(( reply_to.clone(), tag.clone(), module.name.clone(), function.name.clone(), args.elements.clone(), ))}