1use std::{collections::HashMap, fmt, str::FromStr};
8
9use bytes::{BufMut, BytesMut};
10
11use super::validators::{validate_param_key, validate_param_value};
12
13use crate::err::{Error, ParamError};
14
15#[repr(transparent)]
21#[derive(Debug, Clone, Default)]
22pub struct Params(HashMap<String, String>);
23
24impl Params {
25 #[must_use]
27 pub fn new() -> Self {
28 Self::default()
29 }
30
31 pub fn clear(&mut self) {
33 self.0.clear();
34 }
35
36 #[must_use]
38 pub fn len(&self) -> usize {
39 self.0.len()
40 }
41
42 #[must_use]
45 pub fn is_empty(&self) -> bool {
46 self.0.is_empty()
47 }
48
49 #[must_use]
51 pub const fn inner(&self) -> &HashMap<String, String> {
52 &self.0
53 }
54
55 pub fn add(&mut self, key: String, value: String) -> Result<(), Error> {
82 validate_param_key(&key)?;
83 validate_param_value(&value)?;
84
85 self.0.insert(key, value);
86
87 Ok(())
88 }
89
90 #[inline]
112 #[allow(clippy::needless_pass_by_value)]
113 pub fn add_param(
114 &mut self,
115 key: impl ToString,
116 value: impl ToString
117 ) -> Result<(), Error> {
118 let key = key.to_string();
119 let value = value.to_string();
120
121 validate_param_key(&key)?;
122 validate_param_value(&value)?;
123
124 self.0.insert(key, value);
125
126 Ok(())
127 }
128
129 #[inline]
138 #[allow(clippy::needless_pass_by_value)]
139 pub fn add_str(
140 &mut self,
141 key: impl ToString,
142 value: impl Into<String>
143 ) -> Result<(), Error> {
144 let key = key.to_string();
145 let value = value.into();
146
147 validate_param_key(&key)?;
148 validate_param_value(&value)?;
149
150 self.0.insert(key, value);
151
152 Ok(())
153 }
154
155 #[inline]
177 #[allow(clippy::needless_pass_by_value)]
178 pub fn add_bool(
179 &mut self,
180 key: impl ToString,
181 value: bool
182 ) -> Result<(), Error> {
183 let key = key.to_string();
184 let v = if value { "true" } else { "false" };
185
186 validate_param_key(&key)?;
187
188 self.add_str(key, v)
189 }
190
191 #[must_use]
205 pub fn contains(&self, key: &str) -> bool {
206 self.0.contains_key(key)
207 }
208
209 pub fn get_fromstr<T, E>(&self, key: &str) -> Result<Option<T>, Error>
238 where
239 T: FromStr<Err = E>,
240 E: std::fmt::Display
241 {
242 self.get_str(key).map_or_else(
243 || Ok(None),
244 |val| {
245 T::from_str(val).map_or_else(
246 |e| Err(Error::Param(ParamError::Value(e.to_string()))),
247 |v| Ok(Some(v))
248 )
249 }
250 )
251 }
252
253 #[must_use]
258 pub fn get_str(&self, key: &str) -> Option<&str> {
259 let kv = self.0.get_key_value(key);
260 if let Some((_k, v)) = kv {
261 return Some(v);
262 }
263 None
264 }
265
266 pub fn get_bool(&self, key: &str) -> Result<Option<bool>, Error> {
271 let Some(v) = self.get_str(key) else {
272 return Ok(None);
273 };
274
275 let v = v.to_ascii_lowercase();
276 match v.as_ref() {
277 "y" | "yes" | "t" | "true" | "1" | "on" => Ok(Some(true)),
278 "n" | "no" | "f" | "false" | "0" | "off" => Ok(Some(false)),
279 _ => Err(Error::Param(ParamError::Value("not boolean".into())))
280 }
281 }
282
283 #[must_use]
285 pub fn into_inner(self) -> HashMap<String, String> {
286 self.0
287 }
288
289 #[must_use]
293 pub fn calc_buf_size(&self) -> usize {
294 let mut size = 0;
295 for (key, value) in &self.0 {
296 size += key.len() + 1; size += value.len() + 1; }
299 size + 1 }
301
302 #[must_use]
304 pub fn serialize(&self) -> Vec<u8> {
305 let mut buf = Vec::new();
306
307 for (key, value) in &self.0 {
308 let k = key.as_bytes();
309 let v = value.as_bytes();
310 for a in k {
311 buf.push(*a);
312 }
313 buf.push(b' ');
314 for a in v {
315 buf.push(*a);
316 }
317 buf.push(b'\n');
318 }
319
320 buf.push(b'\n');
321
322 buf
323 }
324
325 pub fn encoder_write(&self, buf: &mut BytesMut) {
327 let size = self.calc_buf_size();
329
330 buf.reserve(size);
332
333 for (key, value) in &self.0 {
335 buf.put(key.as_bytes());
336 buf.put_u8(b' ');
337 buf.put(value.as_bytes());
338 buf.put_u8(b'\n');
339 }
340 buf.put_u8(b'\n');
341 }
342}
343
344
345impl Params {
346 #[cfg(feature = "bin")]
354 #[cfg_attr(docsrs, doc(cfg(feature = "bin")))]
355 pub fn encode_buf(
356 &mut self,
357 key: impl Into<String>,
358 buf: &[u8]
359 ) -> Result<(), Error> {
360 self.add(key.into(), base85::encode(buf))?;
361 Ok(())
362 }
363
364 #[cfg(feature = "bin")]
372 #[cfg_attr(docsrs, doc(cfg(feature = "bin")))]
373 pub fn decode_buf(&self, key: &str) -> Result<Option<Vec<u8>>, Error> {
374 let Some(b85) = self.get_str(key) else {
375 return Ok(None);
376 };
377 let buf = base85::decode(b85)
378 .map_err(|_| Error::Param(ParamError::Value("invalid base85".into())))?;
379 Ok(Some(buf))
380 }
381
382 #[cfg(feature = "bincode")]
389 #[cfg_attr(docsrs, doc(cfg(feature = "bincode")))]
390 pub fn encode<E>(
391 &mut self,
392 key: impl Into<String>,
393 data: E
394 ) -> Result<(), Error>
395 where
396 E: bincode::Encode
397 {
398 let conf = bincode::config::standard();
399
400 let buf = bincode::encode_to_vec(data, conf)
401 .map_err(|e| Error::SerializeError(e.to_string()))?;
402
403 self.encode_buf(key, &buf)?;
404
405 Ok(())
406 }
407
408 #[cfg(feature = "bincode")]
414 #[cfg_attr(docsrs, doc(cfg(feature = "bincode")))]
415 pub fn decode<D>(&self, key: &str) -> Result<Option<D>, Error>
416 where
417 D: bincode::Decode<()>
418 {
419 let Some(buf) = self.decode_buf(key)? else {
420 return Ok(None);
421 };
422
423 let conf = bincode::config::standard();
424
425 let (data, _) = bincode::decode_from_slice(&buf, conf)
426 .map_err(|e| Error::Param(ParamError::Value(e.to_string())))?;
427
428 Ok(Some(data))
429 }
430}
431
432#[cfg(test)]
433#[cfg(feature = "bin")]
434mod buf_tests {
435 use super::Params;
436
437 #[test]
438 fn enc_dec() {
439 let buf = orphanage::buf::random(2048);
440
441 let mut params = Params::new();
442 params.encode_buf("Bytes", &buf).unwrap();
443
444 let buf2 = params.decode_buf("Bytes").unwrap().unwrap();
445 assert_eq!(buf, buf2);
446 }
447}
448
449
450impl Params {
451 pub fn encode_anon_list<T, I, F, E>(&mut self, it: I, f: F) -> Result<(), E>
497 where
498 I: IntoIterator<Item = T>,
499 F: Fn(T, &mut Vec<(String, String)>) -> Result<(), E>,
500 E: From<Error>
501 {
502 let mut count = 0;
503
504 let mut recs = 0;
506
507 for (idx, rec) in it.into_iter().enumerate() {
508 let mut rec_kv = Vec::with_capacity(recs);
509
510 f(rec, &mut rec_kv)?;
512
513 recs = std::cmp::max(recs, rec_kv.len());
515
516 for (k, v) in rec_kv {
518 let key = format!("{k}.{idx}");
519 self.add(key, v)?;
520 }
521
522 count += 1;
524 }
525
526 self.add_param("Count", count)?;
527
528 Ok(())
529 }
530
531 pub fn decode_anon_list<T, F, E>(
569 &self,
570 keys: &[&str],
571 f: F
572 ) -> Result<Vec<T>, E>
573 where
574 F: Fn(&HashMap<&str, &str>) -> Result<T, E>,
575 E: From<Error>
576 {
577 let mut ret = Vec::new();
578 let mut recmap: HashMap<&str, &str> = HashMap::new();
579
580 let count = self.get_fromstr::<usize, _>("Count")?.ok_or_else(|| {
582 Error::Param(ParamError::Key("Missing 'Count'".into()))
583 })?;
584
585 for idx in 0..count {
586 recmap.clear();
587
588 for (k, ki) in keys.iter().map(|k| (k, format!("{k}.{idx}",))) {
589 let Some(v) = self.0.get(&ki) else {
590 continue;
591 };
592 recmap.insert(k, v);
593 }
594
595 let vecrec = f(&recmap)?;
596 ret.push(vecrec);
597 }
598
599 Ok(ret)
600 }
601
602 pub fn encode_named_list<T, I, F, E>(
612 &mut self,
613 name: &str,
614 it: I,
615 f: F
616 ) -> Result<(), E>
617 where
618 I: IntoIterator<Item = T>,
619 F: Fn(T, &mut Vec<(String, String)>) -> Result<(), E>,
620 E: From<Error>
621 {
622 let mut count = 0;
623
624 let mut recs = 0;
626
627 for (idx, rec) in it.into_iter().enumerate() {
628 let mut rec_kv = Vec::with_capacity(recs);
629
630 f(rec, &mut rec_kv)?;
632
633 recs = std::cmp::max(recs, rec_kv.len());
635
636 for (k, v) in rec_kv {
638 let key = format!("{name}.{k}.{idx}");
639 self.add(key, v)?;
640 }
641
642 count += 1;
644 }
645
646 let key = format!("{name}.Count");
647 self.add_param(key, count)?;
648
649 Ok(())
650 }
651
652 pub fn decode_named_list<T, F, E>(
659 &self,
660 name: &str,
661 keys: &[&str],
662 f: F
663 ) -> Result<Vec<T>, E>
664 where
665 F: Fn(&HashMap<&str, &str>) -> Result<T, E>,
666 E: From<Error>
667 {
668 let mut ret = Vec::new();
669 let mut recmap: HashMap<&str, &str> = HashMap::new();
670
671 let key = format!("{name}.Count");
673 let count = self.get_fromstr::<usize, _>(&key)?.ok_or_else(|| {
674 Error::Param(ParamError::Key("Missing 'Count'".into()))
675 })?;
676
677 for idx in 0..count {
678 recmap.clear();
679
680 for (k, ki) in keys.iter().map(|k| (k, format!("{name}.{k}.{idx}",))) {
681 let Some(v) = self.0.get(&ki) else {
682 continue;
683 };
684 recmap.insert(k, v);
685 }
686
687 let vecrec = f(&recmap)?;
688 ret.push(vecrec);
689 }
690
691 Ok(ret)
692 }
693}
694
695
696impl TryFrom<HashMap<String, String>> for Params {
698 type Error = Error;
699
700 fn try_from(hm: HashMap<String, String>) -> Result<Self, Self::Error> {
701 for (k, v) in &hm {
702 validate_param_key(k)?;
703 validate_param_value(v)?;
704 }
705 Ok(Self(hm))
706 }
707}
708
709impl fmt::Display for Params {
712 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
713 let mut kvlist = Vec::new();
714 for (key, value) in &self.0 {
715 kvlist.push(format!("{key}={value}"));
716 }
717 write!(f, "{{{}}}", kvlist.join(","))
718 }
719}
720
721
722#[cfg(test)]
723mod tests {
724 use super::Params;
725
726 #[test]
727 fn string() {
728 let mut msg = Params::new();
729
730 msg.add_str("Foo", "bar").unwrap();
731 assert_eq!(msg.get_str("Foo").unwrap(), "bar");
732
733 assert_eq!(msg.get_str("Moo"), None);
734 }
735
736 #[test]
737 fn exists() {
738 let mut params = Params::new();
739
740 params.add_str("foo", "bar").unwrap();
741 assert!(params.contains("foo"));
742
743 assert!(!params.contains("nonexistent"));
744 }
745
746 #[test]
747 fn empty_value() {
748 let mut params = Params::new();
749
750 params.add_str("foo", "").unwrap();
751
752 assert_eq!(params.get_str("foo"), Some(""));
753 }
754
755 #[test]
756 fn integer() {
757 let mut msg = Params::new();
758
759 msg.add_str("Num", "64").unwrap();
760 assert_eq!(msg.get_fromstr::<u16, _>("Num").unwrap().unwrap(), 64);
761 }
762
763 #[test]
764 fn size() {
765 let mut msg = Params::new();
766
767 msg.add_param("Num", 7_usize).unwrap();
768 assert_eq!(msg.get_fromstr::<usize, _>("Num").unwrap().unwrap(), 7);
769 }
770
771 #[test]
772 fn intoparams() {
773 let mut msg = Params::new();
774
775 msg.add_str("Foo", "bar").unwrap();
776 assert_eq!(msg.get_str("Foo").unwrap(), "bar");
777 assert_eq!(msg.get_str("Moo"), None);
778
779 let hm = msg.into_inner();
780 let kv = hm.get_key_value("Foo");
781 if let Some((_k, v)) = kv {
782 assert_eq!(v, "bar");
783 }
784 }
785
786 #[test]
787 fn display() {
788 let mut params = Params::new();
789
790 params.add_str("foo", "bar").unwrap();
791 let s = format!("{params}");
792 assert_eq!(s, "{foo=bar}");
793 }
794
795 #[test]
796 fn ser_size() {
797 let mut params = Params::new();
798
799 params.add_str("foo", "bar").unwrap();
800 params.add_str("moo", "cow").unwrap();
801
802 let sz = params.calc_buf_size();
803
804 assert_eq!(sz, 8 + 8 + 1);
805 }
806
807 #[test]
808 #[should_panic(expected = "Param(Key(\"invalid character\"))")]
809 fn key_invalid_char() {
810 let mut param = Params::new();
811 param.add_str("hell o", "world").unwrap();
812 }
813
814 #[test]
815 #[should_panic(expected = "Param(Key(\"empty\"))")]
816 fn empty_key() {
817 let mut param = Params::new();
818 param.add_str("", "world").unwrap();
819 }
820
821 #[test]
822 #[should_panic(expected = "Param(Value(\"contains newline\"))")]
823 fn value_newline() {
824 let mut param = Params::new();
825 param.add_str("greeting", "hello\nworld").unwrap();
826 }
827
828 #[test]
829 fn boolvals() {
830 let mut params = Params::new();
831
832 params.add_bool("abool", true).unwrap();
833 params.add_bool("abooltoo", false).unwrap();
834
835 let Ok(Some(true)) = params.get_bool("abool") else {
836 panic!("Unexpectedly not Ok(true)");
837 };
838 let Ok(Some(false)) = params.get_bool("abooltoo") else {
839 panic!("Unexpectedly not Ok(false)");
840 };
841 }
842
843 #[test]
844 #[should_panic(expected = "Param(Value(\"not boolean\"))")]
845 fn bad_bool() {
846 let mut params = Params::new();
847
848 params.add_str("fool", "uncertain").unwrap();
849
850 params.get_bool("fool").unwrap();
851 }
852}
853
854
855#[cfg(test)]
856mod recvec_tests {
857 use super::{Error, Params};
858
859 struct Agent {
860 name: String,
861 age: u8
862 }
863
864 impl Agent {
865 fn new(name: impl Into<String>, age: u8) -> Self {
866 Self {
867 name: name.into(),
868 age
869 }
870 }
871 }
872
873 #[test]
874 fn encode_anon() {
875 let mut params = Params::new();
876
877 let agents = vec![Agent::new("frank", 42), Agent::new("anon", 32)];
878
879 params
880 .encode_anon_list::<_, _, _, Error>(agents, |agent, v| {
881 v.push(("Name".to_string(), agent.name));
882 v.push(("Age".to_string(), agent.age.to_string()));
883 Ok(())
884 })
885 .unwrap();
886
887 assert_eq!(params.get_fromstr::<usize, _>("Count").unwrap().unwrap(), 2);
888
889 assert_eq!(params.get_str("Name.0"), Some("frank"));
890 assert_eq!(params.get_str("Age.0"), Some("42"));
891 assert_eq!(params.get_str("Name.1"), Some("anon"));
892 assert_eq!(params.get_str("Age.1"), Some("32"));
893 }
894
895 #[test]
896 fn decode_anon() {
897 let mut params = Params::new();
898 params.add_param("Name.0", "frank").unwrap();
899 params.add_param("Age.0", "42").unwrap();
900 params.add_param("Name.1", "anon").unwrap();
901 params.add_param("Age.1", "32").unwrap();
902 params.add_param("Count", "2").unwrap();
903
904 let v = params
905 .decode_anon_list::<_, _, Error>(&["Name", "Age"], |recmap| {
906 let name = (*recmap.get("Name").unwrap()).to_string();
907 let age = recmap.get("Age").unwrap();
908 let age = age.parse::<u8>().unwrap();
909 Ok(Agent { name, age })
910 })
911 .unwrap();
912
913 assert_eq!(v.len(), 2);
914 assert_eq!(&v[0].name, "frank");
915 assert_eq!(v[0].age, 42);
916 assert_eq!(&v[1].name, "anon");
917 assert_eq!(v[1].age, 32);
918 }
919
920 #[test]
921 #[should_panic(expected = "Param(Key(\"Missing 'Count'\"))")]
922 fn decode_no_count() {
923 let params = Params::new();
924 let _v = params
925 .decode_anon_list::<_, _, Error>(&["Name", "Age"], |recmap| {
926 let name = (*recmap.get("Name").unwrap()).to_string();
927 let age = recmap.get("Age").unwrap();
928 let age = age.parse::<u8>().unwrap();
929 Ok(Agent { name, age })
930 })
931 .unwrap();
932 }
933
934 #[test]
935 #[should_panic(expected = "Param(Value(\"invalid digit found in string\"))")]
936 fn decode_bad_count() {
937 let mut params = Params::new();
938 params.add_param("Count", "moo").unwrap();
939 let _v = params
940 .decode_anon_list::<_, _, Error>(&["Name", "Age"], |recmap| {
941 let name = (*recmap.get("Name").unwrap()).to_string();
942 let age = recmap.get("Age").unwrap();
943 let age = age.parse::<u8>().unwrap();
944 Ok(Agent { name, age })
945 })
946 .unwrap();
947 }
948
949 #[test]
950 fn encode_named() {
951 let mut params = Params::new();
952
953 let agents = vec![Agent::new("frank", 42), Agent::new("anon", 32)];
954
955 params
956 .encode_named_list::<_, _, _, Error>("Agents", agents, |agent, v| {
957 v.push(("Name".to_string(), agent.name));
958 v.push(("Age".to_string(), agent.age.to_string()));
959 Ok(())
960 })
961 .unwrap();
962
963 assert_eq!(
964 params
965 .get_fromstr::<usize, _>("Agents.Count")
966 .unwrap()
967 .unwrap(),
968 2
969 );
970
971 assert_eq!(params.get_str("Agents.Name.0"), Some("frank"));
972 assert_eq!(params.get_str("Agents.Age.0"), Some("42"));
973 assert_eq!(params.get_str("Agents.Name.1"), Some("anon"));
974 assert_eq!(params.get_str("Agents.Age.1"), Some("32"));
975 }
976
977 #[test]
978 fn decode_named() {
979 let mut params = Params::new();
980 params.add_param("Agents.Name.0", "frank").unwrap();
981 params.add_param("Agents.Age.0", "42").unwrap();
982 params.add_param("Agents.Name.1", "anon").unwrap();
983 params.add_param("Agents.Age.1", "32").unwrap();
984 params.add_param("Agents.Count", "2").unwrap();
985
986 let v = params
987 .decode_named_list::<_, _, Error>("Agents", &["Name", "Age"], |recmap| {
988 let name = (*recmap.get("Name").unwrap()).to_string();
989 let age = recmap.get("Age").unwrap();
990 let age = age.parse::<u8>().unwrap();
991 Ok(Agent { name, age })
992 })
993 .unwrap();
994
995 assert_eq!(v.len(), 2);
996 assert_eq!(&v[0].name, "frank");
997 assert_eq!(v[0].age, 42);
998 assert_eq!(&v[1].name, "anon");
999 assert_eq!(v[1].age, 32);
1000 }
1001}
1002
1003