匹配并执行相同的功能块,但类型除外

Match and do the same function block except for a type

我需要执行与 Some(Md5Sess) 中相同的操作,仅更改调用 digest 的类型。因此,从 <md5::Md5>::digest 更改为 <sha2::Sha256>::digest 等,可能还有许多其他更改:

match challenge.algorithm {
    Some(Md5Sess) => {
        //I need to repeat this entire block, only changing the `md5::Md5` 
        //by the correct hashing function
        let a1_part1 =
            <md5::Md5>::digest(format!("{}:{}:{}", username, realm, password).as_bytes());
        let cnonce = match cnonce {
            Some(cnonce) => cnonce,
            None => return Err(DigestError::MissingCNonce),
        };
        let a1_part2 = format!("{}:{}", nonce, cnonce);
        a1 = format!("{:x}:{}", a1_part1, a1_part2);
        let entity_body = match &body {
            Some(body) => body.as_ref(),
            None => "".as_bytes(),
        };
        hash_common::<md5::Md5>(
            method,
            chosen_qop,
            a1,
            nonce,
            Some(cnonce),
            nonce_count,
            uri,
            body,
        )
    }
    Some(Sha512Trunc256Sess) => 
        Err(DigestError::DigestAlgorithmNotImplemented(Sha512Trunc256Sess)),
    Some(Sha256Sess) => 
        Err(DigestError::DigestAlgorithmNotImplemented(Sha256Sess)),
    Some(Algorithm::Other(s)) => 
        Err(DigestError::DigestAlgorithmNotImplemented(Algorithm::Other(s))),
}

我唯一的想法是为该块中使用的每个变量创建一个在散列类型上通用的函数,具有大量参数的不便。

有没有更好的方法解决这个问题?

我也尝试过使用宏,只记得在 Rust 中,宏不像在 C 中那样不关心正在使用的文本。我做了一个与散列类型匹配的宏,如 my_macro!(md5::Md5) 但随后它抱怨块中使用的变量。

免责声明:我不认为这是最好的解决方案,因为我可能更愿意尽可能使用函数,但如果那是不可能的,那就是:

duplicate 可以帮助您在所有匹配案例中重复使用您的块:

use duplicate::duplicate:

duplicate! {
    [
        func(hash_type);
        [
            //I need to repeat this entire block, only changing the `md5::Md5` by the correct hashing function
            let a1_part1 = <hash_type>::digest(format!("{}:{}:{}", username, realm, password).as_bytes());
            let cnonce = match cnonce {
                Some(cnonce) => cnonce,
                None => return Err(DigestError::MissingCNonce)
            };
            let a1_part2 = format!("{}:{}", nonce, cnonce);
            a1 = format!("{:x}:{}", a1_part1, a1_part2);
            let entity_body = match &body {
                Some(body) => body.as_ref(),
                None => "".as_bytes()
            };
            hash_common::<hash_type>(method, chosen_qop, a1, nonce, Some(cnonce), nonce_count, uri, body)
        ];
    ]
    match challenge.algorithm {
        Some(Md5Sess) => {
            func([md5::Md5]) // Duplicates the block with hash_type = md5::Md5
        },
        Some(Sha512Trunc256Sess) => {
            func([sha2::Sha256])// Duplicates the block with hash_type = sha2::Sha256
        },
        ...
    }
}

这将在每个匹配案例中重复函数体(已经超出其原始块并进入替换),将 hash_type 替换为您在 func([md5::Md5]) 中提供的哈希类型, func([sha2::Sha256]),等等

您可以先选择要应用的函数,然后处理数据:

// Select the functions to apply
let (digest, common) = match challenge.algorithm {
    Some (Md5Sess) => (<md5::Md5>::digest, hash_common::<md5::Md5>),
    Some (Sha256Sess) => (<sha2::Sha256>::digest, hash_common::<sha2::Sha256>),
    _ => todo!(),
}

// Now process the data
let a1_part1 = digest (format!("{}:{}:{}", username, realm, password).as_bytes());
let cnonce = match cnonce {
    Some(cnonce) => cnonce,
    None => return Err (DigestError::MissingCNonce)
};
let a1_part2 = format!("{}:{}", nonce, cnonce);
a1 = format!("{:x}:{}", a1_part1, a1_part2);
let entity_body = match &body {
    Some (body) => body.as_ref(),
    None => "".as_bytes()
};
common (method, chosen_qop, a1, nonce, Some (cnonce), nonce_count, uri, body)