macro_rules! at_forwarders {
(
$view:ident, $field:ident, $client:literal,
bare { $( fn $bn:ident( $($ba:ident: $bt:ty),* $(,)? ) -> $br:ty; )* }
dir { $( fn $dn:ident( $($da:ident: $dt:ty),* $(,)? ) -> $dr:ty; )* }
$( raw { $( fn $rn:ident( $($ra:ident: $rt:ty),* $(,)? ) -> $rr:ty => $rtgt:ident; )* } )?
) => { ... };
}Expand description
Generate the cwd-bound forwarders for a CLI wrapper’s …At view.
Each CLI wrapper (vcs-git, vcs-jj, vcs-github, vcs-gitlab, vcs-gitea)
exposes a cwd-bound view — GitAt, JjAt, GitHubAt, GitLabAt, GiteaAt —
that holds a reference to the client plus a pre-bound dir, and re-exposes the
client’s methods with dir already supplied. The forwarder bodies are
byte-identical across the five backends but for a handful of names, so they live
here once instead of as a copied macro_rules! per crate:
$view— the bound view type (e.g.GitAt). It must be generic over<'a, R: ProcessRunner>and have a field named$fieldholding the client plus adir: &'a Pathfield.$field— the inner field naming the client (e.g.git,gh,glab,tea).$client— a string literal naming the client type, used in the generated doc strings and rendered as an intra-doc link (e.g."Git"→[`Git`]).bare { … }— methods forwarded verbatim toself.$field. Reserve this for the genuinely dir-independent calls (version,capabilities, aclone/git_clonethat names its own destination): the view dropsdirentirely, so abaremethod never touches it.dir { … }— methods that takeself.diras their first argument.raw { fn view(args…) -> Ret => target; … }— the raw escape hatches (run/run_raw/run_args/run_raw_args). These used to sit inbare, sogit.at(dir).run(…)silently ran in the process cwd, not the bounddir— a bound handle whose raw call could hit a different repository (M15/T-035). They are now bound: the view methodviewforwards to the client’s dir-takingtarget(self.$field.target(self.dir, args…)), so a raw call through the view runs indirlike every other…Atmethod. The process-cwd escape hatch is still there — callrun/run_raw/… on the client itself (git.run(…)), not through.at(dir).
The argument and return types in the method lists resolve in the calling
crate, so they are written exactly as that wrapper’s own methods are. The
ProcessRunner bound is fully qualified (::processkit::ProcessRunner) so the
expansion compiles regardless of which items the caller has imported.
vcs_cli_support::at_forwarders! {
GitAt, git, "Git",
bare { fn version() -> Result<String>; }
dir { fn status() -> Result<Vec<StatusEntry>>; }
raw { fn run(args: &[String]) -> Result<String> => run_in; }
}