rust小技巧
記錄一些覺得在rust中很有趣的寫法
情景:返回不同type
- 不想使用dyn來改變return value的type,使用enum來進行不同值轉換
- 這邊的情況會是希望根據使用者輸入資料返回不同加密algorithm的結果
- 但我不想要為每一個都編寫不同函數,太攏長而且沒必要
type HmacSha256 = Hmac<Sha256>;
type HmacSha512 = Hmac<Sha512>;
enum HmacType {
Sha256(HmacSha256),
Sha512(HmacSha512)
}
fn convert_hmac(key: String,message: String,num: i8) -> HmacType {
match num {
2 => {
let mut mac: HmacSha512 = HmacSha512::new_from_slice(key.as_bytes())
.expect("failed to convert to sha512 hmac");
mac.update(message.as_bytes());
HmacType::Sha512(mac)
}
_ => {
let mut mac: HmacSha256 = HmacSha256::new_from_slice(key.as_bytes())
.expect("failed to convert to sha256 hmac");
mac.update(message.as_bytes());
HmacType::Sha256(mac)
}
}
}
這時候會發現原先mac的底下的method已經沒辦法使用
- 編寫trait來滿足需求
- 由於使用enum並不會直接滿足mac底下的method,因此需要調用clone完成
- 不滿足的原因是因為這是enum借用出來的mutable reference,Rust不允許把他移出enum,也就是改變值
trait VerifyHmac {
fn verify_slice(&mut self,tag: &[u8]) -> Result<(), MacError>;
}
impl VerifyHmac for HmacType {
fn verify_slice(&mut self, tag: &[u8]) -> Result<(), MacError> {
match self {
HmacType::Sha256(hmac) => hmac.clone().verify_slice(tag),
HmacType::Sha512(hmac) => hmac.clone().verify_slice(tag),
}
}
}
至此就可以輕鬆地調用了
pub fn verify(key: String, message: String,code: String,num: i8){
let mut mac = convert_hmac(key, message, num);
let code_bytes =hex::decode (code).expect("cannot convert string to hex");
match mac.verify_slice(&code_bytes) {
Ok(()) => println!("Hmac驗證成功!訊息完整且金鑰正確"),
Err(..) => println!("Hmac驗證失敗!可能訊息被篡改或金鑰不正確"),
}
}