I previously showed and explained how to compute the binary logarithm of a pure fraction (that is, 0 < a < 1) in fixed-point arithmetic. As the asker notes, the integer portion of a binary logarithm can be computed using a count-leading-zero primitive (clz). One therefore splits the integer input x like so: x = a * 2**expo, and computes expo via clz and log2(a) using the algorithm I demonstrated previously.
I do not know Rust, so the code below was written in ISO-C99, which I hope can be translated to Rust in a straightforward manner. The clz functionality is implemented manually here. Obviously one would want to avail oneself of appropriate built-ins for this where available.
The specification given by asker stated that the result be returned in UQ64.64 format which seemed unusual to me, so the ilog2() function here returns a UQ16.16 result. If a result in UQ64.64 format is definitely required, a conversion is easily accomplished by converting the result of ilog2() to a __uint128_t and performing a left shift by 48 on he result.
I have included some light-weight test scaffolding to demonstrate the correct operation of the code. Using built-ins for clz should result in about 50 to 60 machine instructions being generated on common CPU architectures like x86-64 and ARM64 when using the latest compilers, so performance should be sufficient for various use cases (the asker did not mention specific performance goals).
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <math.h>
#define TEST_LIMIT (1ULL << 25)
uint32_t clz32 (uint32_t x)
{
    uint32_t n = 32;
    uint32_t y;
    
    y = x >> 16; if (y != 0) { n = n - 16; x = y; }
    y = x >>  8; if (y != 0) { n = n -  8; x = y; }
    y = x >>  4; if (y != 0) { n = n -  4; x = y; }
    y = x >>  2; if (y != 0) { n = n -  2; x = y; }
    y = x >>  1; if (y != 0) return n - 2;
    return n - x;
}
uint32_t clz64 (uint64_t a)
{
    uint32_t ahi = (uint32_t)(a >> 32);
    uint32_t alo = (uint32_t)(a);
    uint32_t res;
    if (ahi) {
        res = 0;
    } else {
        res = 32;
        ahi = alo;
    }
    res = res + clz32 (ahi);
    return res;
}
/* compute log2(x) for x in [1,2**64-1]; result is a UQ16.16 accurate to 6 fractional bits */
uint32_t ilog2 (uint64_t x)
{
    uint32_t a, t, one = ((uint32_t)1) << 31; // UQ1.31
    uint32_t r = 0; // UQ16.16
    uint32_t lz, expo;
    /* split: x = a * 2**expo, 0 < a < 1 */
    lz = clz64 (x);
    expo = 64 - lz;
    a = (uint32_t)((x << lz) >> (64 - 31)); // UQ1.31
    /* try factors (1+2**(-i)) with i = 1, ..., 8 */
    if ((t = a + (a >> 1)) < one) { a = t; r += 0x095c0; }
    if ((t = a + (a >> 2)) < one) { a = t; r += 0x0526a; }
    if ((t = a + (a >> 3)) < one) { a = t; r += 0x02b80; }
    if ((t = a + (a >> 4)) < one) { a = t; r += 0x01664; }
    if ((t = a + (a >> 5)) < one) { a = t; r += 0x00b5d; }
    if ((t = a + (a >> 6)) < one) { a = t; r += 0x005ba; }
    if ((t = a + (a >> 7)) < one) { a = t; r += 0x002e0; }
    if ((t = a + (a >> 8)) < one) { a = t; r += 0x00171; }
    r = (expo << 16) - r; // adjust for split of argument
    r = ((r + (1 << 9)) >> (16 - 6)) << (16 - 6); // round to 6 fractional bits
    return r;
}
int main (void)
{
    uint32_t ir;
    uint64_t errloc = 0, ix = 1;
    const double two_to_16 = 65536.0;
    double res, ref;
    double err, maxerr = 0;
    do {
        ir = ilog2 (ix);
        res = (double)ir / two_to_16;
        ref = log2 ((double)ix);
        err = fabs (res - ref);
        if (err > maxerr) {
            maxerr =  err;
            errloc = ix;
        }
        ix += 1;
        if ((ix & 0xffffff) == 0) printf ("\r%" PRIx64, ix);
    } while (ix < TEST_LIMIT);
    printf ("\nmaxerr = %.8f @ %" PRIu64 "\n", maxerr, errloc);
    return EXIT_SUCCESS;
}