Subject: [bug#77093] [PATCH rust-team v3 14/17] build-system: cargo: Add ‘cargo-inputs’.

From: Ludovic Courtès <[email-masked]>
Date: Tue, 22 Apr 2025 23:20:00 +0200

Hello,

Hilton Chain <[email-masked]> writes:

> * gnu/packages/rust-crates.scm: New file.
> * gnu/packages/rust-sources.scm: New file.
> * gnu/local.mk (GNU_SYSTEM_MODULES): Regisiter them.
> * guix/build-system/cargo.scm (crate-source,cargo-inputs): New procedures.
> * guix/import/crate.scm: Hide ‘crate-source’ from (guix build-system cargo).
> * etc/teams/rust/audit-rust-crates: New file.
> * etc/teams/rust/cleanup-crates.sh: New file.
> * etc/teams/rust/rust-crates.tmpl: New file.
>
> Change-Id: I2f2d705a3e376ed3c646f31b824052a2278d4fb3

I’m late to the party and coming mostly to discuss the color of the
bikeshed—the bikeshed looks really great regardless of the color anyway.
:-)

>  etc/teams/rust/audit-rust-crates | 70 ++++++++++++++++++++++++++++++++
>  etc/teams/rust/cleanup-crates.sh | 37 +++++++++++++++++

Maybe not a blocker, but we should plan to move from awk + sh to Scheme.

> +;;; Rust dependencies fetched from crates.io and non-workspace development
> +;;; snapshots.
> +;;;
> +
> +(define qqqq-separator 'begin-of-crates)
> +
> +(define ssss-separator 'end-of-crates)

I couldn’t find where these markers are actually used.  Would be nice if
it could be avoided, somehow.

> +(define* (cargo-inputs name #:key (crates-module '(gnu packages rust-crates))
> +                       (sources-module '(gnu packages rust-sources)))
> +
> +  "Given symbol NAME, resolve variable 'NAME-cargo-inputs', an input list, in
> +CRATES-MODULE, return its copy with #f removed and symbols resolved to
> +variables defined in SOURCES-MODULE if the input list exists, otherwise return
> +an empty list."
> +  (let loop ((inputs
> +              (catch #t
> +                (lambda ()
> +                  (module-ref (resolve-interface crates-module)
> +                              (symbol-append name '-cargo-inputs)))

My preference would be to use a first-class hash table instead of
playing tricks with the module system at run time: that would be more
discoverable, more predictable (no computed variable names), and
future-proof (should the module system introspection capabilities vanish
or become less powerful/risky).

So I would arrange to have something like:

  (define-cargo-inputs lookup-input
    (NAME => (list …))
    …)

and that would expand to something like:

  (define lookup-input
    (let ((table (make-hash-table)))
      (hashq-set! 'NAME (list …))
      (lambda (name)
        "Return the inputs for NAME."
        (hashq-ref table name))))

I was in the mood for macrology, so here’s a macro that does it:

  (define-syntax define-cargo-inputs
    (syntax-rules (=>)
      ((_ lookup inputs ...)
       (define lookup
         (let ((table (make-hash-table)))
           (letrec-syntax ((record
                            (syntax-rules (=>)
                              ((_) #t)
                              ((_ (name => lst) rest (... ...))
                               (begin
                                 (hashq-set! table 'name lst)
                                 (record rest (... ...)))))))
               (record inputs ...)
               (lambda (name)
                 "Return the inputs for NAME."
                 (hashq-ref table name))))))))

Ludo’.