From 2e0732e579d883caf33de5c339f170c6d3378d73 Mon Sep 17 00:00:00 2001 From: h7x4 Date: Fri, 13 Dec 2024 17:06:28 +0100 Subject: [PATCH] commands: verify key uniqueness for ResponseAttributes -> HashMap --- src/commands.rs | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index ff9008e..28fbb36 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -1,4 +1,7 @@ -use std::{collections::HashMap, str::SplitWhitespace}; +use std::{ + collections::{HashMap, HashSet}, + str::SplitWhitespace, +}; use crate::Request; @@ -114,7 +117,7 @@ pub type GenericResponseResult<'a> = Result, &'a str>; pub type GenericResponse<'a> = HashMap<&'a str, GenericResponseValue<'a>>; -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum GenericResponseValue<'a> { Text(&'a str), Binary(&'a [u8]), @@ -144,6 +147,11 @@ impl<'a> From>> for ResponseAttributes impl<'a> From> for HashMap<&'a str, GenericResponseValue<'a>> { fn from(val: ResponseAttributes<'a>) -> Self { + debug_assert!({ + let mut uniq = HashSet::new(); + val.0.iter().all(move |x| uniq.insert(*x)) + }); + val.0.into_iter().collect() } } @@ -258,3 +266,39 @@ pub(crate) use get_and_parse_optional_property; pub(crate) use get_and_parse_property; pub(crate) use get_optional_property; pub(crate) use get_property; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg(debug_assertions)] + fn test_valid_hashmap_uniqueness_assert() { + let valid_maplike_attrs: ResponseAttributes = vec![ + ("a", GenericResponseValue::Text("1")), + ("A", GenericResponseValue::Text("2")), + ("A ", GenericResponseValue::Text("3")), + ("b", GenericResponseValue::Text("4")), + ] + .into(); + + let map: HashMap<_, _> = valid_maplike_attrs.into(); + assert_eq!(map.len(), 4); + } + + #[test] + #[cfg(debug_assertions)] + #[should_panic] + fn test_invalid_hashmap_uniqueness_assert() { + let invalid_maplike_attrs: ResponseAttributes = vec![ + ("a", GenericResponseValue::Text("1")), + ("b", GenericResponseValue::Text("2")), + ("c", GenericResponseValue::Text("3")), + ("a", GenericResponseValue::Text("4")), + ] + .into(); + + let map: HashMap<_, _> = invalid_maplike_attrs.into(); + assert_eq!(map.len(), 4); + } +}