#rust #repeat
Вопрос:
Мне нужно выполнить те же операции , что и в 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 amp;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), но затем он пожаловался на переменные, используемые в блоке.
Комментарии:
1. Что такое
hash_common
и почему он принимает алгоритм в качестве параметра типа?2. @LambdaFairy это еще одна функция, которая выполняет некоторые общие функции, используемые всеми блоками. Я вижу, что вы думаете, что я могу просто поместить свой блок внутри функции hash_function, но это невозможно. Этот блок предназначен только для
HashSess
случаев совпадения. Я скрыл случаи, не связанные с sess, потому что они просто звонятhash_common
напрямую
Ответ №1:
Возможно, вы сможете сделать это, сначала выбрав функции для применения, а затем манипулируя данными:
// 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 amp;body {
Some (body) => body.as_ref(),
None => "".as_bytes()
};
common (method, chosen_qop, a1, nonce, Some (cnonce), nonce_count, uri, body)
Комментарии:
1. это хороший ifea. К сожалению, я спрятал несколько дел. Есть
HashSess
случаи, когда применяется этот блок кода, но естьHash
случаи, для которых блок не применяется. Знаете ли вы элегантное решение для применения блокаHashSess
и другого блокаHash
?2. Если вы хотите включить или отключить части обработки, вы можете использовать функцию возврата соответствия
Option
вместо прямой, чтобы затемif let
применять или не применять каждую часть.3. К сожалению, это не работает:
Some (Sha256Sess) => (<sha2::Sha256>::digest, hash_common::<sha2::Sha256>), | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct
md5::Md5, found struct
sha2::Sha2`. Полная ошибка: pastebin.com/TryKVucK4. Выходные
fn
данные имеют внутренний тип, называемыйOutput
. Этот внутренний тип изменяется в соответствии с хэш-функцией. Таким образом, эти функции не могут быть все одного типа, как того требуетmatch
5. Затем вы можете обернуть функцию в замыкание, которое унифицирует тип возвращаемого значения:
|s| <md5::Md5>::digest (s).as_bytes()
.
Ответ №2:
Отказ от ответственности: Я не утверждаю, что это лучшее решение, так как я, вероятно, предпочел бы использовать функцию, если это вообще возможно, но если об этом не может быть и речи, вот:
Дубликат может помочь вам повторно использовать ваш блок во всех случаях совпадения:
use duplicate::duplicate_inline:
duplicate_inline! {
[
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 amp;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])
, и т.д.