1use {
2 base64::{engine::general_purpose::STANDARD as BASE64_ENGINE, Engine},
3 chrono::{DateTime, FixedOffset, Utc},
4 std::{
5 collections::{
6 hash_map::{Drain, Entry, IntoIter, IntoKeys, IntoValues, Iter, IterMut, Keys, Values, ValuesMut},
7 HashMap, TryReserveError,
8 },
9 fmt::{Display, Formatter, Result as FmtResult},
10 hash::Hash,
11 iter::{Extend, FromIterator, IntoIterator},
12 net::{IpAddr, Ipv4Addr, Ipv6Addr},
13 ops::Index,
14 panic::UnwindSafe,
15 },
16};
17
18#[derive(Clone, Debug)]
23pub struct SessionData {
24 variables: HashMap<String, SessionValue>,
26}
27
28impl SessionData {
29 pub fn new() -> Self {
34 Self {
35 variables: HashMap::new(),
36 }
37 }
38
39 pub fn with_capacity(capacity: usize) -> Self {
41 Self {
42 variables: HashMap::with_capacity(capacity),
43 }
44 }
45
46 pub fn capacity(&self) -> usize {
51 self.variables.capacity()
52 }
53
54 pub fn clear(&mut self) {
56 self.variables.clear();
57 }
58
59 pub fn contains_key<Q: AsRef<str> + ?Sized>(&self, k: &Q) -> bool {
61 self.variables.contains_key(&k.as_ref().to_lowercase())
62 }
63
64 pub fn drain(&mut self) -> Drain<'_, String, SessionValue> {
69 self.variables.drain()
70 }
71
72 pub fn entry<Q: AsRef<str> + ?Sized>(&mut self, key: &Q) -> Entry<'_, String, SessionValue> {
74 self.variables.entry(key.as_ref().to_lowercase())
75 }
76
77 pub fn get<Q: AsRef<str> + ?Sized>(&self, key: &Q) -> Option<&SessionValue> {
79 self.variables.get(&key.as_ref().to_lowercase())
80 }
81
82 pub fn get_key_value<Q: AsRef<str> + ?Sized>(&self, key: &Q) -> Option<(&str, &SessionValue)> {
84 self.variables.get_key_value(&key.as_ref().to_lowercase()).map(|(key, value)| (key.as_str(), value))
85 }
86
87 pub fn get_mut<Q: AsRef<str> + ?Sized>(&mut self, key: &Q) -> Option<&mut SessionValue> {
89 self.variables.get_mut(&key.as_ref().to_lowercase())
90 }
91
92 pub fn insert<Q: AsRef<str> + ?Sized>(&mut self, key: &Q, value: SessionValue) -> Option<SessionValue> {
97 self.variables.insert(key.as_ref().to_lowercase(), value)
98 }
99
100 pub fn into_keys(self) -> IntoKeys<String, SessionValue> {
103 self.variables.into_keys()
104 }
105
106 pub fn into_values(self) -> IntoValues<String, SessionValue> {
109 self.variables.into_values()
110 }
111
112 pub fn iter(&self) -> Iter<'_, String, SessionValue> {
115 self.variables.iter()
116 }
117
118 pub fn iter_mut(&mut self) -> IterMut<'_, String, SessionValue> {
121 self.variables.iter_mut()
122 }
123
124 pub fn is_empty(&self) -> bool {
126 self.variables.is_empty()
127 }
128
129 pub fn keys(&self) -> Keys<'_, String, SessionValue> {
131 self.variables.keys()
132 }
133
134 pub fn len(&self) -> usize {
136 self.variables.len()
137 }
138
139 pub fn remove<Q: AsRef<str> + ?Sized>(&mut self, key: &Q) -> Option<SessionValue> {
141 self.variables.remove(&key.as_ref().to_lowercase())
142 }
143
144 pub fn remove_entry<Q: AsRef<str> + ?Sized>(&mut self, key: &Q) -> Option<(String, SessionValue)> {
146 self.variables.remove_entry(&key.as_ref().to_lowercase())
147 }
148
149 pub fn reserve(&mut self, additional: usize) {
157 self.variables.reserve(additional)
158 }
159
160 pub fn retain<F: FnMut(&str, &mut SessionValue) -> bool>(&mut self, mut f: F) {
165 self.variables.retain(|key, value| f(key.as_str(), value))
166 }
167
168 pub fn shrink_to(&mut self, min_capacity: usize) {
173 self.variables.shrink_to(min_capacity)
174 }
175
176 pub fn shrink_to_fit(&mut self) {
179 self.variables.shrink_to_fit()
180 }
181
182 pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
191 self.variables.try_reserve(additional)
192 }
193
194 pub fn values(&self) -> Values<'_, String, SessionValue> {
196 self.variables.values()
197 }
198
199 pub fn values_mut(&mut self) -> ValuesMut<'_, String, SessionValue> {
201 self.variables.values_mut()
202 }
203}
204
205impl Default for SessionData {
206 fn default() -> Self {
207 Self::new()
208 }
209}
210
211impl<'a, K: AsRef<str> + ?Sized> Extend<(&'a K, &'a SessionValue)> for SessionData {
212 fn extend<T: IntoIterator<Item = (&'a K, &'a SessionValue)>>(&mut self, iter: T) {
213 self.variables.extend(iter.into_iter().map(|(key, value)| (key.as_ref().to_lowercase(), value.clone())));
214 }
215}
216
217impl From<HashMap<String, SessionValue>> for SessionData {
218 fn from(variables: HashMap<String, SessionValue>) -> Self {
219 let mut my_vars = HashMap::new();
220 for (key, value) in variables.iter() {
221 my_vars.insert(key.to_lowercase(), value.clone());
222 }
223
224 Self {
225 variables: my_vars,
226 }
227 }
228}
229
230impl<K: AsRef<str>, const N: usize> From<[(K, SessionValue); N]> for SessionData {
231 fn from(variables: [(K, SessionValue); N]) -> Self {
232 let mut my_vars = HashMap::new();
233 for (key, value) in variables.iter() {
234 my_vars.insert(key.as_ref().to_lowercase(), value.clone());
235 }
236
237 Self {
238 variables: my_vars,
239 }
240 }
241}
242
243impl<K: AsRef<str>> FromIterator<(K, SessionValue)> for SessionData {
244 fn from_iter<T: IntoIterator<Item = (K, SessionValue)>>(iter: T) -> Self {
245 let mut my_vars = HashMap::new();
246 for (key, value) in iter {
247 my_vars.insert(key.as_ref().to_lowercase(), value.clone());
248 }
249
250 Self {
251 variables: my_vars,
252 }
253 }
254}
255
256impl<Q: AsRef<str> + ?Sized> Index<&'_ Q> for SessionData {
257 type Output = SessionValue;
258
259 fn index(&self, key: &Q) -> &Self::Output {
260 self.variables.get(&key.as_ref().to_lowercase()).unwrap()
261 }
262}
263
264impl<'a> IntoIterator for &'a SessionData {
265 type Item = (&'a String, &'a SessionValue);
266 type IntoIter = Iter<'a, String, SessionValue>;
267
268 fn into_iter(self) -> Self::IntoIter {
269 self.variables.iter()
270 }
271}
272
273impl<'a> IntoIterator for &'a mut SessionData {
274 type Item = (&'a String, &'a mut SessionValue);
275 type IntoIter = IterMut<'a, String, SessionValue>;
276
277 fn into_iter(self) -> Self::IntoIter {
278 self.variables.iter_mut()
279 }
280}
281
282impl IntoIterator for SessionData {
283 type Item = (String, SessionValue);
284 type IntoIter = IntoIter<String, SessionValue>;
285
286 fn into_iter(self) -> Self::IntoIter {
287 self.variables.into_iter()
288 }
289}
290
291impl UnwindSafe for SessionData {}
292
293impl PartialEq for SessionData {
294 fn eq(&self, other: &Self) -> bool {
295 self.variables == other.variables
296 }
297}
298
299impl PartialEq<HashMap<String, SessionValue>> for SessionData {
300 fn eq(&self, other: &HashMap<String, SessionValue>) -> bool {
301 if self.variables.len() != other.len() {
302 return false;
303 }
304
305 for (key, other_value) in other.iter() {
306 match self.variables.get(&key.to_lowercase()) {
307 None => return false,
308 Some(value) => {
309 if value != other_value {
310 return false;
311 }
312 }
313 }
314 }
315
316 true
317 }
318}
319
320impl Eq for SessionData {}
321
322#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
324pub enum SessionValue {
325 Null,
327
328 Binary(Vec<u8>),
330
331 Bool(bool),
333
334 Integer(i64),
336
337 IpAddr(IpAddr),
339
340 String(String),
342
343 Timestamp(DateTime<Utc>),
345}
346
347impl SessionValue {
348 #[inline]
350 pub fn is_null(&self) -> bool {
351 matches!(self, Self::Null)
352 }
353
354 pub fn as_variable_value(&self) -> String {
356 match self {
357 Self::Null => "".to_string(),
358 Self::Binary(value) => BASE64_ENGINE.encode(value),
359 Self::Bool(b) => if *b {
360 "true"
361 } else {
362 "false"
363 }
364 .to_string(),
365 Self::Integer(i) => format!("{i}"),
366 Self::IpAddr(ip) => format!("{ip}"),
367 Self::String(s) => s.clone(),
368 Self::Timestamp(t) => format!("{}", t.format("%Y-%m-%dT%H:%M:%SZ")),
369 }
370 }
371}
372
373impl From<bool> for SessionValue {
374 fn from(value: bool) -> Self {
375 Self::Bool(value)
376 }
377}
378
379impl From<i64> for SessionValue {
380 fn from(value: i64) -> Self {
381 Self::Integer(value)
382 }
383}
384
385impl From<IpAddr> for SessionValue {
386 fn from(value: IpAddr) -> Self {
387 Self::IpAddr(value)
388 }
389}
390
391impl From<Ipv4Addr> for SessionValue {
392 fn from(value: Ipv4Addr) -> Self {
393 Self::IpAddr(IpAddr::V4(value))
394 }
395}
396
397impl From<Ipv6Addr> for SessionValue {
398 fn from(value: Ipv6Addr) -> Self {
399 Self::IpAddr(IpAddr::V6(value))
400 }
401}
402
403impl From<&str> for SessionValue {
404 fn from(value: &str) -> Self {
405 Self::String(value.to_string())
406 }
407}
408
409impl From<String> for SessionValue {
410 fn from(value: String) -> Self {
411 Self::String(value)
412 }
413}
414
415impl From<DateTime<FixedOffset>> for SessionValue {
416 fn from(value: DateTime<FixedOffset>) -> Self {
417 Self::Timestamp(value.into())
418 }
419}
420
421impl From<DateTime<Utc>> for SessionValue {
422 fn from(value: DateTime<Utc>) -> Self {
423 Self::Timestamp(value)
424 }
425}
426
427impl Display for SessionValue {
428 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
429 match self {
430 Self::Null => f.write_str("null"),
431 Self::Binary(value) => f.write_str(&BASE64_ENGINE.encode(value)),
432 Self::Bool(b) => Display::fmt(b, f),
433 Self::Integer(i) => Display::fmt(i, f),
434 Self::IpAddr(ip) => Display::fmt(ip, f),
435 Self::String(s) => f.write_str(s),
436 Self::Timestamp(t) => write!(f, "{}", t.format("%Y-%m-%dT%H:%M:%SZ")),
437 }
438 }
439}
440
441#[cfg(test)]
442mod tests {
443 use {
444 super::{SessionData, SessionValue},
445 chrono::{DateTime, FixedOffset, NaiveDate, Utc},
446 std::{
447 cmp::Ordering,
448 collections::hash_map::{DefaultHasher, HashMap},
449 hash::{Hash, Hasher},
450 iter::IntoIterator,
451 net::{IpAddr, Ipv4Addr, Ipv6Addr},
452 },
453 };
454
455 #[test]
456 fn check_session_value_derived() {
457 let sv1a = SessionValue::Null;
458 let sv1b = SessionValue::Null;
459 let sv2 = SessionValue::Bool(true);
460 let values = vec![
461 SessionValue::Null,
462 SessionValue::Bool(false),
463 SessionValue::Bool(true),
464 SessionValue::Integer(-1),
465 SessionValue::Integer(0),
466 SessionValue::Integer(1),
467 SessionValue::IpAddr(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))),
468 SessionValue::IpAddr(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1))),
469 SessionValue::String("test1".to_string()),
470 SessionValue::String("test2".to_string()),
471 ];
472 let display = ["null", "false", "true", "-1", "0", "1", "127.0.0.1", "::1", "test1", "test2"];
473 assert_eq!(sv1a, sv1b);
474 assert_ne!(sv1a, sv2);
475 assert_eq!(sv1a, sv1a.clone());
476
477 let mut h1a = DefaultHasher::new();
479 let mut h1b = DefaultHasher::new();
480 let mut h2 = DefaultHasher::new();
481 sv1a.hash(&mut h1a);
482 sv1b.hash(&mut h1b);
483 sv2.hash(&mut h2);
484 let hash1a = h1a.finish();
485 let hash1b = h1b.finish();
486 let hash2 = h2.finish();
487 assert_eq!(hash1a, hash1b);
488 assert_ne!(hash1a, hash2);
489
490 for i in 0..values.len() {
492 for j in 0..values.len() {
493 assert_eq!(values[i].cmp(&values[j]), i.cmp(&j));
494
495 match i.cmp(&j) {
496 Ordering::Less => assert!(values[i] < values[j]),
497 Ordering::Equal => assert!(values[i] == values[j]),
498 Ordering::Greater => assert!(values[i] > values[j]),
499 }
500 }
501 }
502
503 for ref value in values.iter() {
505 let _ = format!("{value:?}");
506 }
507
508 for i in 0..values.len() {
510 assert_eq!(values[i].to_string(), display[i]);
511 }
512 }
513
514 #[test]
515 fn check_case_sensitivity() {
516 let mut sd = SessionData::new();
517 assert!(sd.is_empty());
518 sd.insert("test", SessionValue::Null);
519 assert!(sd.contains_key("TEST"));
520 assert!(sd.contains_key("test"));
521
522 sd.insert("Test", SessionValue::Bool(true));
523 sd.insert("TeST2", SessionValue::Integer(100));
524 assert!(sd.contains_key("tEsT"));
525 assert!(sd.contains_key("test"));
526
527 assert_eq!(sd.len(), 2);
528 assert!(!sd.is_empty());
529 assert_eq!(sd.get("test"), Some(&SessionValue::Bool(true)));
530 assert!(sd.contains_key("tEsT"));
531 assert!(sd.contains_key("test"));
532 assert_eq!(sd.get_key_value("tEST"), Some(("test", &SessionValue::Bool(true))));
533
534 let sv = sd.get_mut("tesT");
535 assert!(sv.is_some());
536 *sv.unwrap() = SessionValue::String("Hello".to_string());
537 assert_eq!(sd.get("test"), Some(&SessionValue::String("Hello".to_string())));
538
539 sd.entry("test2").and_modify(|v| *v = SessionValue::Integer(200));
540 assert_eq!(sd["test2"], SessionValue::Integer(200));
541
542 assert!(sd.remove("teST").is_some());
543 assert!(sd.remove("test").is_none());
544 assert!(sd.remove_entry("test2").is_some());
545 }
546
547 #[test]
548 fn check_clone_eq() {
549 let mut sd1 = SessionData::new();
550 sd1.insert("test", SessionValue::String("Hello World".to_string()));
551 let sd2 = sd1.clone();
552 assert_eq!(sd1, sd2);
553
554 let mut sd3 = SessionData::with_capacity(1);
555 assert!(sd3.capacity() > 0);
556 sd3.insert("TEST", SessionValue::String("Hello World".to_string()));
557 assert_eq!(sd1, sd3);
558 sd3.drain();
559 assert_ne!(sd1, sd3);
560 sd3.insert("test", SessionValue::String("Hello again".to_string()));
561 assert_ne!(sd1, sd3);
562 sd3.insert("test", SessionValue::Integer(1));
563 assert_ne!(sd1, sd3);
564 sd3.clear();
565 sd3.insert("TeST", SessionValue::String("Hello World".to_string()));
566 assert_eq!(sd1, sd3);
567
568 let mut h = HashMap::with_capacity(1);
569 h.insert("test".to_string(), SessionValue::String("Hello World".to_string()));
570 assert_eq!(sd1, h);
571 h.drain();
572 assert_ne!(sd1, h);
573 h.insert("test".to_string(), SessionValue::String("Hello again".to_string()));
574 assert_ne!(sd1, h);
575 h.insert("test".to_string(), SessionValue::Integer(1));
576 assert_ne!(sd1, h);
577 h.insert("test".to_string(), SessionValue::String("Hello World".to_string()));
578 assert_eq!(sd1, h);
579 h.drain();
580 h.insert("test2".to_string(), SessionValue::String("Hello World".to_string()));
581 assert_ne!(sd1, h);
582
583 sd1.clear();
584 sd1.shrink_to_fit();
585 assert_eq!(sd1.capacity(), 0);
586 sd1.reserve(100);
587 assert!(sd1.capacity() >= 100);
588 sd1.shrink_to(50);
589 assert!(sd1.capacity() >= 50);
590
591 let _ = format!("{sd1:?}");
593 }
594
595 #[test]
596 fn check_from_hashmap() {
597 let mut h = HashMap::new();
598 h.insert("Test".to_string(), SessionValue::String("Hello World".to_string()));
599 let mut sd = SessionData::from(h);
600 assert_eq!(sd.len(), 1);
601 assert_eq!(sd["test"], SessionValue::String("Hello World".to_string()));
602
603 let to_add = [("Test2", SessionValue::Integer(100)), ("Test3", SessionValue::Bool(true))];
604
605 sd.extend(to_add.iter().map(|r| (r.0, &r.1)));
606 assert_eq!(sd.len(), 3);
607 assert_eq!(sd["test2"], SessionValue::Integer(100));
608 assert_eq!(sd["test3"], SessionValue::Bool(true));
609 }
610
611 #[test]
612 fn check_from_array() {
613 let values: [(String, SessionValue); 3] = [
614 ("Test".to_string(), SessionValue::String("Hello World".to_string())),
615 ("Test2".to_string(), SessionValue::Integer(100)),
616 ("Test3".to_string(), SessionValue::Bool(true)),
617 ];
618 let sd = SessionData::from(values);
619 assert_eq!(sd.len(), 3);
620 assert_eq!(sd["test"], SessionValue::String("Hello World".to_string()));
621 assert_eq!(sd["test2"], SessionValue::Integer(100));
622 assert_eq!(sd["test3"], SessionValue::Bool(true));
623 }
624
625 #[test]
626 fn check_from_iter() {
627 let values = vec![
628 ("Test".to_string(), SessionValue::String("Hello World".to_string())),
629 ("Test2".to_string(), SessionValue::Integer(100)),
630 ("Test3".to_string(), SessionValue::Bool(true)),
631 ];
632 let sd = SessionData::from_iter(values);
633 assert_eq!(sd.len(), 3);
634 assert_eq!(sd["test"], SessionValue::String("Hello World".to_string()));
635 assert_eq!(sd["test2"], SessionValue::Integer(100));
636 assert_eq!(sd["test3"], SessionValue::Bool(true));
637 }
638
639 #[test]
640 fn check_keys() {
641 let mut sd: SessionData = Default::default();
642 sd.try_reserve(3).unwrap();
643 sd.insert("test1", SessionValue::Null);
644 sd.insert("TEst2", SessionValue::Bool(true));
645 sd.insert("tesT3", SessionValue::Integer(1));
646
647 let mut test1_seen = false;
648 let mut test2_seen = false;
649 let mut test3_seen = false;
650 for key in sd.keys() {
651 match key.as_str() {
652 "test1" => {
653 assert!(!test1_seen);
654 test1_seen = true;
655 }
656 "test2" => {
657 assert!(!test2_seen);
658 test2_seen = true;
659 }
660 "test3" => {
661 assert!(!test3_seen);
662 test3_seen = true;
663 }
664 _ => panic!("Unexpected key: {key}"),
665 }
666 }
667 assert!(test1_seen);
668 assert!(test2_seen);
669 assert!(test3_seen);
670
671 test1_seen = false;
672 test2_seen = false;
673 test3_seen = false;
674 for key in sd.into_keys() {
675 match key.as_str() {
676 "test1" => {
677 assert!(!test1_seen);
678 test1_seen = true;
679 }
680 "test2" => {
681 assert!(!test2_seen);
682 test2_seen = true;
683 }
684 "test3" => {
685 assert!(!test3_seen);
686 test3_seen = true;
687 }
688 _ => panic!("Unexpected key: {key}"),
689 }
690 }
691 assert!(test1_seen);
692 assert!(test2_seen);
693 assert!(test3_seen);
694 }
695
696 #[test]
697 #[allow(clippy::manual_range_contains)]
698 fn check_values() {
699 let mut sd: SessionData = Default::default();
700 sd.try_reserve(3).unwrap();
701 sd.insert("test0", SessionValue::Null);
702 sd.insert("TEst1", SessionValue::from(true));
703 sd.insert("tesT2", SessionValue::from(1));
704 sd.insert("tESt3", SessionValue::from(Ipv4Addr::new(192, 0, 2, 1)));
705 sd.insert("tESt4", SessionValue::from(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)));
706 sd.insert("tESt5", SessionValue::from(IpAddr::V4(Ipv4Addr::new(192, 0, 2, 2))));
707 sd.insert("tESt6", SessionValue::from("Hello World"));
708 sd.insert(
709 "test7",
710 SessionValue::from(DateTime::<Utc>::from_utc(
711 NaiveDate::from_ymd_opt(2019, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap(),
712 Utc,
713 )),
714 );
715 sd.insert("test8", SessionValue::Binary(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
716 sd.insert("test9", SessionValue::from(false));
717 sd.insert("test10", SessionValue::from("Hello World2".to_string()));
718 sd.insert(
719 "test11",
720 SessionValue::from(DateTime::<FixedOffset>::from_local(
721 NaiveDate::from_ymd_opt(2019, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap(),
722 FixedOffset::west_opt(8 * 3600).unwrap(),
723 )),
724 );
725
726 let mut test_seen = [false; 12];
727 for value in sd.values_mut() {
728 match value {
729 SessionValue::Null => {
730 assert!(!test_seen[0]);
731 assert!(value.is_null());
732 assert_eq!(value.as_variable_value(), "");
733 test_seen[0] = true;
734 *value = SessionValue::Integer(100);
735 }
736 SessionValue::Bool(true) => {
737 assert!(!value.is_null());
738 assert!(!test_seen[1]);
739 assert_eq!(value.as_variable_value(), "true");
740 test_seen[1] = true;
741 *value = SessionValue::Integer(101);
742 }
743 SessionValue::Integer(1) => {
744 assert!(!value.is_null());
745 assert!(!test_seen[2]);
746 assert_eq!(value.as_variable_value(), "1");
747 test_seen[2] = true;
748 *value = SessionValue::Integer(102);
749 }
750 SessionValue::IpAddr(IpAddr::V4(v4)) if v4 == &Ipv4Addr::new(192, 0, 2, 1) => {
751 assert!(!value.is_null());
752 assert!(!test_seen[3]);
753 assert_eq!(value.as_variable_value(), "192.0.2.1");
754 test_seen[3] = true;
755 *value = SessionValue::Integer(103);
756 }
757 SessionValue::IpAddr(IpAddr::V6(v6)) if v6 == &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1) => {
758 assert!(!value.is_null());
759 assert!(!test_seen[4]);
760 assert_eq!(value.as_variable_value(), "2001:db8::1");
761 test_seen[4] = true;
762 *value = SessionValue::Integer(104);
763 }
764 SessionValue::IpAddr(IpAddr::V4(v4)) if v4 == &Ipv4Addr::new(192, 0, 2, 2) => {
765 assert!(!value.is_null());
766 assert!(!test_seen[5]);
767 assert_eq!(value.as_variable_value(), "192.0.2.2");
768 test_seen[5] = true;
769 *value = SessionValue::Integer(105);
770 }
771 SessionValue::String(s) if s == "Hello World" => {
772 assert!(!value.is_null());
773 assert!(!test_seen[6]);
774 assert_eq!(value.as_variable_value(), "Hello World");
775 test_seen[6] = true;
776 *value = SessionValue::Integer(106);
777 }
778 SessionValue::Timestamp(dt)
779 if dt
780 == &DateTime::<Utc>::from_utc(
781 NaiveDate::from_ymd_opt(2019, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap(),
782 Utc,
783 ) =>
784 {
785 assert!(!value.is_null());
786 assert!(!test_seen[7]);
787 assert_eq!(value.as_variable_value(), "2019-01-01T00:00:00Z");
788 assert_eq!(format!("{value}"), "2019-01-01T00:00:00Z");
789 test_seen[7] = true;
790 *value = SessionValue::Integer(107);
791 }
792 SessionValue::Binary(v) => {
793 assert_eq!(v, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
794 assert!(!value.is_null());
795 assert!(!test_seen[8]);
796 assert_eq!(value.as_variable_value(), "AAECAwQFBgcICQ==");
797 assert_eq!(format!("{value}"), "AAECAwQFBgcICQ==");
798 test_seen[8] = true;
799 *value = SessionValue::Integer(108);
800 }
801 SessionValue::Bool(false) => {
802 assert!(!value.is_null());
803 assert!(!test_seen[9]);
804 assert_eq!(value.as_variable_value(), "false");
805 test_seen[9] = true;
806 *value = SessionValue::Integer(109);
807 }
808 SessionValue::String(s) if s == "Hello World2" => {
809 assert!(!value.is_null());
810 assert!(!test_seen[10]);
811 assert_eq!(value.as_variable_value(), "Hello World2");
812 test_seen[10] = true;
813 *value = SessionValue::Integer(110);
814 }
815 SessionValue::Timestamp(dt)
816 if dt
817 == &DateTime::<Utc>::from_utc(
818 NaiveDate::from_ymd_opt(2019, 1, 1).unwrap().and_hms_opt(8, 0, 0).unwrap(),
819 Utc,
820 ) =>
821 {
822 assert!(!value.is_null());
823 assert!(!test_seen[11]);
824 assert_eq!(value.as_variable_value(), "2019-01-01T08:00:00Z");
825 assert_eq!(format!("{value}"), "2019-01-01T08:00:00Z");
826 test_seen[11] = true;
827 *value = SessionValue::Integer(111);
828 }
829 _ => panic!("Unexpected value: {value}"),
830 }
831 }
832
833 assert!(test_seen.iter().all(|&v| v));
834 test_seen.iter_mut().for_each(|v| *v = false);
835
836 let test_range = 100i64..(100i64 + test_seen.len() as i64);
837
838 for value in sd.values() {
839 match value {
840 SessionValue::Integer(i) if test_range.contains(i) => {
841 let i = (i - 100) as usize;
842 assert!(!test_seen[i]);
843 test_seen[i] = true;
844 }
845 _ => panic!("Unexpected value: {value}"),
846 }
847 }
848
849 assert!(test_seen.iter().all(|&v| v));
850 test_seen.iter_mut().for_each(|v| *v = false);
851 for value in sd.into_values() {
852 match value {
853 SessionValue::Integer(i) if test_range.contains(&i) => {
854 let i = (i - 100) as usize;
855 assert!(!test_seen[i]);
856 test_seen[i] = true;
857 }
858 _ => panic!("Unexpected value: {value}"),
859 }
860 }
861 assert!(test_seen.iter().all(|&v| v));
862 }
863
864 #[test]
865 fn check_iter() {
866 let mut sd: SessionData = Default::default();
867 sd.try_reserve(3).unwrap();
868 sd.insert("test1", SessionValue::Null);
869 sd.insert("TEst2", SessionValue::Bool(true));
870 sd.insert("tesT3", SessionValue::Integer(1));
871
872 let mut test1_seen = false;
873 let mut test2_seen = false;
874 let mut test3_seen = false;
875 for (key, value) in sd.iter_mut() {
876 match key.as_str() {
877 "test1" => {
878 assert_eq!(value, &SessionValue::Null);
879 assert!(!test1_seen);
880 *value = SessionValue::Integer(100);
881 test1_seen = true;
882 }
883 "test2" => {
884 assert_eq!(value, &SessionValue::Bool(true));
885 assert!(!test2_seen);
886 *value = SessionValue::Integer(101);
887 test2_seen = true;
888 }
889 "test3" => {
890 assert_eq!(value, &SessionValue::Integer(1));
891 assert!(!test3_seen);
892 *value = SessionValue::Integer(102);
893 test3_seen = true;
894 }
895 _ => panic!("Unexpected value: {value}"),
896 }
897 }
898 assert!(test1_seen);
899 assert!(test2_seen);
900 assert!(test3_seen);
901
902 let mut test1_seen = false;
903 let mut test2_seen = false;
904 let mut test3_seen = false;
905 for (key, value) in sd.iter() {
906 match key.as_str() {
907 "test1" => {
908 assert_eq!(value, &SessionValue::Integer(100));
909 assert!(!test1_seen);
910 test1_seen = true;
911 }
912 "test2" => {
913 assert_eq!(value, &SessionValue::Integer(101));
914 assert!(!test2_seen);
915 test2_seen = true;
916 }
917 "test3" => {
918 assert_eq!(value, &SessionValue::Integer(102));
919 assert!(!test3_seen);
920 test3_seen = true;
921 }
922 _ => panic!("Unexpected key: {key}"),
923 }
924 }
925 assert!(test1_seen);
926 assert!(test2_seen);
927 assert!(test3_seen);
928
929 let mut sd_mut = sd.clone();
930
931 test1_seen = false;
932 test2_seen = false;
933 test3_seen = false;
934 for (key, value) in (&sd).into_iter() {
935 match key.as_str() {
936 "test1" => {
937 assert_eq!(value, &SessionValue::Integer(100));
938 assert!(!test1_seen);
939 test1_seen = true;
940 }
941 "test2" => {
942 assert_eq!(value, &SessionValue::Integer(101));
943 assert!(!test2_seen);
944 test2_seen = true;
945 }
946 "test3" => {
947 assert_eq!(value, &SessionValue::Integer(102));
948 assert!(!test3_seen);
949 test3_seen = true;
950 }
951 _ => panic!("Unexpected key: {key}"),
952 }
953 }
954 assert!(test1_seen);
955 assert!(test2_seen);
956 assert!(test3_seen);
957
958 test1_seen = false;
959 test2_seen = false;
960 test3_seen = false;
961 for (key, value) in sd.into_iter() {
962 match key.as_str() {
963 "test1" => {
964 assert_eq!(value, SessionValue::Integer(100));
965 assert!(!test1_seen);
966 test1_seen = true;
967 }
968 "test2" => {
969 assert_eq!(value, SessionValue::Integer(101));
970 assert!(!test2_seen);
971 test2_seen = true;
972 }
973 "test3" => {
974 assert_eq!(value, SessionValue::Integer(102));
975 assert!(!test3_seen);
976 test3_seen = true;
977 }
978 _ => panic!("Unexpected key: {key}"),
979 }
980 }
981 assert!(test1_seen);
982 assert!(test2_seen);
983 assert!(test3_seen);
984
985 sd_mut.retain(|k, _| k != "test3");
986
987 test1_seen = false;
988 test2_seen = false;
989 test3_seen = false;
990 for (key, value) in (&mut sd_mut).into_iter() {
991 match key.as_str() {
992 "test1" => {
993 assert_eq!(value, &SessionValue::Integer(100));
994 assert!(!test1_seen);
995 test1_seen = true;
996 }
997 "test2" => {
998 assert_eq!(value, &SessionValue::Integer(101));
999 assert!(!test2_seen);
1000 test2_seen = true;
1001 }
1002 _ => panic!("Unexpected key: {key}"),
1003 }
1004 }
1005 assert!(test1_seen);
1006 assert!(test2_seen);
1007 assert!(!test3_seen);
1008 }
1009}
1010