1use std::fmt;
30use std::hash::Hash;
31use std::ops::Deref;
32
33use serde::{Deserialize, Serialize};
34
35#[derive(Debug, Clone, PartialEq, Eq)]
37pub struct ValidationError {
38 pub type_name: &'static str,
40 pub message: String,
42}
43
44impl fmt::Display for ValidationError {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 write!(f, "{}: {}", self.type_name, self.message)
47 }
48}
49
50impl std::error::Error for ValidationError {}
51
52#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
92#[serde(transparent)]
93pub struct OperationId(String);
94
95impl OperationId {
96 pub fn new(id: impl Into<String>) -> Result<Self, ValidationError> {
100 let id = id.into();
101 if id.is_empty() {
102 return Err(ValidationError {
103 type_name: "OperationId",
104 message: "value cannot be empty".to_string(),
105 });
106 }
107 Ok(Self(id))
108 }
109
110 #[inline]
115 pub fn new_unchecked(id: impl Into<String>) -> Self {
116 Self(id.into())
117 }
118
119 #[inline]
121 pub fn into_inner(self) -> String {
122 self.0
123 }
124
125 #[inline]
127 pub fn as_str(&self) -> &str {
128 &self.0
129 }
130}
131
132impl fmt::Display for OperationId {
133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 write!(f, "{}", self.0)
135 }
136}
137
138impl Deref for OperationId {
139 type Target = str;
140
141 #[inline]
142 fn deref(&self) -> &Self::Target {
143 &self.0
144 }
145}
146
147impl AsRef<str> for OperationId {
148 #[inline]
149 fn as_ref(&self) -> &str {
150 &self.0
151 }
152}
153
154impl From<String> for OperationId {
155 #[inline]
156 fn from(s: String) -> Self {
157 Self(s)
158 }
159}
160
161impl From<&str> for OperationId {
162 #[inline]
163 fn from(s: &str) -> Self {
164 Self(s.to_string())
165 }
166}
167
168#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
215#[serde(transparent)]
216pub struct ExecutionArn(String);
217
218impl ExecutionArn {
219 pub fn new(arn: impl Into<String>) -> Result<Self, ValidationError> {
224 let arn = arn.into();
225 Self::validate(&arn)?;
226 Ok(Self(arn))
227 }
228
229 #[inline]
234 pub fn new_unchecked(arn: impl Into<String>) -> Self {
235 Self(arn.into())
236 }
237
238 #[inline]
240 pub fn into_inner(self) -> String {
241 self.0
242 }
243
244 #[inline]
246 pub fn as_str(&self) -> &str {
247 &self.0
248 }
249
250 fn validate(value: &str) -> Result<(), ValidationError> {
258 if value.is_empty() {
259 return Err(ValidationError {
260 type_name: "ExecutionArn",
261 message: "value cannot be empty".to_string(),
262 });
263 }
264
265 if !value.starts_with("arn:") {
268 return Err(ValidationError {
269 type_name: "ExecutionArn",
270 message: "must start with 'arn:'".to_string(),
271 });
272 }
273
274 if !value.contains(":lambda:") {
276 return Err(ValidationError {
277 type_name: "ExecutionArn",
278 message: "must contain ':lambda:' service identifier".to_string(),
279 });
280 }
281
282 if !value.contains(":durable:") {
283 return Err(ValidationError {
284 type_name: "ExecutionArn",
285 message: "must contain ':durable:' segment".to_string(),
286 });
287 }
288
289 Ok(())
290 }
291}
292
293impl fmt::Display for ExecutionArn {
294 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
295 write!(f, "{}", self.0)
296 }
297}
298
299impl Deref for ExecutionArn {
300 type Target = str;
301
302 #[inline]
303 fn deref(&self) -> &Self::Target {
304 &self.0
305 }
306}
307
308impl AsRef<str> for ExecutionArn {
309 #[inline]
310 fn as_ref(&self) -> &str {
311 &self.0
312 }
313}
314
315impl From<String> for ExecutionArn {
316 #[inline]
317 fn from(s: String) -> Self {
318 Self(s)
319 }
320}
321
322impl From<&str> for ExecutionArn {
323 #[inline]
324 fn from(s: &str) -> Self {
325 Self(s.to_string())
326 }
327}
328
329#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
366#[serde(transparent)]
367pub struct CallbackId(String);
368
369impl CallbackId {
370 pub fn new(id: impl Into<String>) -> Result<Self, ValidationError> {
374 let id = id.into();
375 if id.is_empty() {
376 return Err(ValidationError {
377 type_name: "CallbackId",
378 message: "value cannot be empty".to_string(),
379 });
380 }
381 Ok(Self(id))
382 }
383
384 #[inline]
389 pub fn new_unchecked(id: impl Into<String>) -> Self {
390 Self(id.into())
391 }
392
393 #[inline]
395 pub fn into_inner(self) -> String {
396 self.0
397 }
398
399 #[inline]
401 pub fn as_str(&self) -> &str {
402 &self.0
403 }
404}
405
406impl fmt::Display for CallbackId {
407 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
408 write!(f, "{}", self.0)
409 }
410}
411
412impl Deref for CallbackId {
413 type Target = str;
414
415 #[inline]
416 fn deref(&self) -> &Self::Target {
417 &self.0
418 }
419}
420
421impl AsRef<str> for CallbackId {
422 #[inline]
423 fn as_ref(&self) -> &str {
424 &self.0
425 }
426}
427
428impl From<String> for CallbackId {
429 #[inline]
430 fn from(s: String) -> Self {
431 Self(s)
432 }
433}
434
435impl From<&str> for CallbackId {
436 #[inline]
437 fn from(s: &str) -> Self {
438 Self(s.to_string())
439 }
440}
441
442#[cfg(test)]
443mod tests {
444 use super::*;
445 use std::collections::HashMap;
446
447 #[test]
450 fn test_operation_id_from_string() {
451 let id = OperationId::from("op-123".to_string());
452 assert_eq!(id.as_str(), "op-123");
453 }
454
455 #[test]
456 fn test_operation_id_from_str() {
457 let id = OperationId::from("op-456");
458 assert_eq!(id.as_str(), "op-456");
459 }
460
461 #[test]
462 fn test_operation_id_into() {
463 let id: OperationId = "op-789".into();
464 assert_eq!(id.as_str(), "op-789");
465 }
466
467 #[test]
468 fn test_operation_id_new_valid() {
469 let id = OperationId::new("op-abc").unwrap();
470 assert_eq!(id.as_str(), "op-abc");
471 }
472
473 #[test]
474 fn test_operation_id_new_empty_rejected() {
475 let result = OperationId::new("");
476 assert!(result.is_err());
477 let err = result.unwrap_err();
478 assert_eq!(err.type_name, "OperationId");
479 assert!(err.message.contains("empty"));
480 }
481
482 #[test]
483 fn test_operation_id_display() {
484 let id = OperationId::from("op-display");
485 assert_eq!(format!("{}", id), "op-display");
486 }
487
488 #[test]
489 fn test_operation_id_debug() {
490 let id = OperationId::from("op-debug");
491 let debug_str = format!("{:?}", id);
492 assert!(debug_str.contains("op-debug"));
493 }
494
495 #[test]
496 fn test_operation_id_deref() {
497 let id = OperationId::from("op-deref-test");
498 assert!(id.starts_with("op-"));
499 assert_eq!(id.len(), 13);
500 }
501
502 #[test]
503 fn test_operation_id_as_ref() {
504 let id = OperationId::from("op-asref");
505 let s: &str = id.as_ref();
506 assert_eq!(s, "op-asref");
507 }
508
509 #[test]
510 fn test_operation_id_hash_and_eq() {
511 let id1 = OperationId::from("op-hash");
512 let id2 = OperationId::from("op-hash");
513 let id3 = OperationId::from("op-different");
514
515 assert_eq!(id1, id2);
516 assert_ne!(id1, id3);
517
518 let mut map: HashMap<OperationId, String> = HashMap::new();
519 map.insert(id1.clone(), "value1".to_string());
520 assert_eq!(map.get(&id2), Some(&"value1".to_string()));
521 assert_eq!(map.get(&id3), None);
522 }
523
524 #[test]
525 fn test_operation_id_serde_roundtrip() {
526 let id = OperationId::from("op-serde-test");
527 let json = serde_json::to_string(&id).unwrap();
528 assert_eq!(json, "\"op-serde-test\"");
529
530 let deserialized: OperationId = serde_json::from_str(&json).unwrap();
531 assert_eq!(deserialized, id);
532 }
533
534 #[test]
535 fn test_operation_id_into_inner() {
536 let id = OperationId::from("op-inner");
537 let inner = id.into_inner();
538 assert_eq!(inner, "op-inner");
539 }
540
541 #[test]
544 fn test_execution_arn_from_string() {
545 let arn = ExecutionArn::from(
546 "arn:aws:lambda:us-east-1:123456789012:function:my-func:durable:abc123".to_string(),
547 );
548 assert!(arn.as_str().starts_with("arn:aws:lambda:"));
549 }
550
551 #[test]
552 fn test_execution_arn_from_str() {
553 let arn =
554 ExecutionArn::from("arn:aws:lambda:us-west-2:123456789012:function:test:durable:xyz");
555 assert!(arn.contains(":durable:"));
556 }
557
558 #[test]
559 fn test_execution_arn_new_valid() {
560 let arn =
561 ExecutionArn::new("arn:aws:lambda:eu-west-1:123456789012:function:func:durable:id123");
562 assert!(arn.is_ok());
563 }
564
565 #[test]
566 fn test_execution_arn_new_empty_rejected() {
567 let result = ExecutionArn::new("");
568 assert!(result.is_err());
569 let err = result.unwrap_err();
570 assert_eq!(err.type_name, "ExecutionArn");
571 assert!(err.message.contains("empty"));
572 }
573
574 #[test]
575 fn test_execution_arn_new_invalid_prefix_rejected() {
576 let result = ExecutionArn::new("not-an-arn");
577 assert!(result.is_err());
578 let err = result.unwrap_err();
579 assert!(err.message.contains("arn:"));
580 }
581
582 #[test]
583 fn test_execution_arn_new_missing_lambda_rejected() {
584 let result = ExecutionArn::new("arn:aws:s3:us-east-1:123456789012:bucket:durable:abc");
585 assert!(result.is_err());
586 let err = result.unwrap_err();
587 assert!(err.message.contains(":lambda:"));
588 }
589
590 #[test]
591 fn test_execution_arn_new_missing_durable_rejected() {
592 let result = ExecutionArn::new("arn:aws:lambda:us-east-1:123456789012:function:my-func");
593 assert!(result.is_err());
594 let err = result.unwrap_err();
595 assert!(err.message.contains(":durable:"));
596 }
597
598 #[test]
599 fn test_execution_arn_new_aws_cn_partition() {
600 let arn = ExecutionArn::new(
601 "arn:aws-cn:lambda:cn-north-1:123456789012:function:my-func:durable:abc123",
602 );
603 assert!(arn.is_ok());
604 }
605
606 #[test]
607 fn test_execution_arn_new_aws_us_gov_partition() {
608 let arn = ExecutionArn::new(
609 "arn:aws-us-gov:lambda:us-gov-west-1:123456789012:function:my-func:durable:abc123",
610 );
611 assert!(arn.is_ok());
612 }
613
614 #[test]
615 fn test_execution_arn_new_aws_iso_partition() {
616 let arn = ExecutionArn::new(
617 "arn:aws-iso:lambda:us-iso-east-1:123456789012:function:my-func:durable:abc123",
618 );
619 assert!(arn.is_ok());
620 }
621
622 #[test]
623 fn test_execution_arn_display() {
624 let arn = ExecutionArn::from("arn:aws:lambda:us-east-1:123456789012:function:f:durable:x");
625 assert_eq!(
626 format!("{}", arn),
627 "arn:aws:lambda:us-east-1:123456789012:function:f:durable:x"
628 );
629 }
630
631 #[test]
632 fn test_execution_arn_deref() {
633 let arn = ExecutionArn::from("arn:aws:lambda:us-east-1:123456789012:function:f:durable:x");
634 assert!(arn.starts_with("arn:"));
635 assert!(arn.contains("lambda"));
636 }
637
638 #[test]
639 fn test_execution_arn_hash_and_eq() {
640 let arn1 = ExecutionArn::from("arn:aws:lambda:us-east-1:123:function:f:durable:a");
641 let arn2 = ExecutionArn::from("arn:aws:lambda:us-east-1:123:function:f:durable:a");
642 let arn3 = ExecutionArn::from("arn:aws:lambda:us-east-1:123:function:f:durable:b");
643
644 assert_eq!(arn1, arn2);
645 assert_ne!(arn1, arn3);
646
647 let mut map: HashMap<ExecutionArn, i32> = HashMap::new();
648 map.insert(arn1.clone(), 42);
649 assert_eq!(map.get(&arn2), Some(&42));
650 }
651
652 #[test]
653 fn test_execution_arn_serde_roundtrip() {
654 let arn = ExecutionArn::from("arn:aws:lambda:us-east-1:123:function:f:durable:serde");
655 let json = serde_json::to_string(&arn).unwrap();
656 let deserialized: ExecutionArn = serde_json::from_str(&json).unwrap();
657 assert_eq!(deserialized, arn);
658 }
659
660 #[test]
663 fn test_callback_id_from_string() {
664 let id = CallbackId::from("callback-123".to_string());
665 assert_eq!(id.as_str(), "callback-123");
666 }
667
668 #[test]
669 fn test_callback_id_from_str() {
670 let id = CallbackId::from("callback-456");
671 assert_eq!(id.as_str(), "callback-456");
672 }
673
674 #[test]
675 fn test_callback_id_new_valid() {
676 let id = CallbackId::new("callback-abc").unwrap();
677 assert_eq!(id.as_str(), "callback-abc");
678 }
679
680 #[test]
681 fn test_callback_id_new_empty_rejected() {
682 let result = CallbackId::new("");
683 assert!(result.is_err());
684 let err = result.unwrap_err();
685 assert_eq!(err.type_name, "CallbackId");
686 assert!(err.message.contains("empty"));
687 }
688
689 #[test]
690 fn test_callback_id_display() {
691 let id = CallbackId::from("callback-display");
692 assert_eq!(format!("{}", id), "callback-display");
693 }
694
695 #[test]
696 fn test_callback_id_deref() {
697 let id = CallbackId::from("callback-deref");
698 assert!(id.starts_with("callback-"));
699 assert_eq!(id.len(), 14);
700 }
701
702 #[test]
703 fn test_callback_id_as_ref() {
704 let id = CallbackId::from("callback-asref");
705 let s: &str = id.as_ref();
706 assert_eq!(s, "callback-asref");
707 }
708
709 #[test]
710 fn test_callback_id_hash_and_eq() {
711 let id1 = CallbackId::from("callback-hash");
712 let id2 = CallbackId::from("callback-hash");
713 let id3 = CallbackId::from("callback-other");
714
715 assert_eq!(id1, id2);
716 assert_ne!(id1, id3);
717
718 let mut map: HashMap<CallbackId, bool> = HashMap::new();
719 map.insert(id1.clone(), true);
720 assert_eq!(map.get(&id2), Some(&true));
721 }
722
723 #[test]
724 fn test_callback_id_serde_roundtrip() {
725 let id = CallbackId::from("callback-serde");
726 let json = serde_json::to_string(&id).unwrap();
727 assert_eq!(json, "\"callback-serde\"");
728
729 let deserialized: CallbackId = serde_json::from_str(&json).unwrap();
730 assert_eq!(deserialized, id);
731 }
732
733 #[test]
736 fn test_validation_error_display() {
737 let err = ValidationError {
738 type_name: "TestType",
739 message: "test error message".to_string(),
740 };
741 assert_eq!(format!("{}", err), "TestType: test error message");
742 }
743
744 #[test]
749 fn test_backward_compat_deserialize_plain_string_to_operation_id() {
750 let existing_json = "\"existing-op-id-12345\"";
752
753 let id: OperationId = serde_json::from_str(existing_json).unwrap();
755 assert_eq!(id.as_str(), "existing-op-id-12345");
756 }
757
758 #[test]
759 fn test_backward_compat_deserialize_plain_string_to_execution_arn() {
760 let existing_json =
762 "\"arn:aws:lambda:us-east-1:123456789012:function:my-func:durable:abc123\"";
763
764 let arn: ExecutionArn = serde_json::from_str(existing_json).unwrap();
766 assert!(arn.contains(":durable:"));
767 }
768
769 #[test]
770 fn test_backward_compat_deserialize_plain_string_to_callback_id() {
771 let existing_json = "\"callback-xyz-789\"";
773
774 let id: CallbackId = serde_json::from_str(existing_json).unwrap();
776 assert_eq!(id.as_str(), "callback-xyz-789");
777 }
778
779 #[test]
782 fn test_backward_compat_impl_into_with_string() {
783 fn accept_operation_id(id: impl Into<OperationId>) -> OperationId {
784 id.into()
785 }
786
787 fn accept_execution_arn(arn: impl Into<ExecutionArn>) -> ExecutionArn {
788 arn.into()
789 }
790
791 fn accept_callback_id(id: impl Into<CallbackId>) -> CallbackId {
792 id.into()
793 }
794
795 let op_id = accept_operation_id("op-123".to_string());
797 assert_eq!(op_id.as_str(), "op-123");
798
799 let op_id = accept_operation_id("op-456");
801 assert_eq!(op_id.as_str(), "op-456");
802
803 let arn =
805 accept_execution_arn("arn:aws:lambda:us-east-1:123:function:f:durable:x".to_string());
806 assert!(arn.contains(":durable:"));
807
808 let cb_id = accept_callback_id("callback-abc");
810 assert_eq!(cb_id.as_str(), "callback-abc");
811 }
812
813 #[test]
816 fn test_backward_compat_serialize_same_as_string() {
817 let op_id = OperationId::from("op-123");
818 let plain_string = "op-123".to_string();
819
820 let op_id_json = serde_json::to_string(&op_id).unwrap();
821 let string_json = serde_json::to_string(&plain_string).unwrap();
822
823 assert_eq!(op_id_json, string_json);
825 assert_eq!(op_id_json, "\"op-123\"");
826 }
827
828 #[test]
830 fn test_backward_compat_string_operations() {
831 let op_id = OperationId::from("op-123-suffix");
832
833 assert!(op_id.starts_with("op-"));
835 assert!(op_id.ends_with("-suffix"));
836 assert!(op_id.contains("123"));
837 assert_eq!(op_id.len(), 13); fn process_str(s: &str) -> String {
841 s.to_uppercase()
842 }
843 assert_eq!(process_str(&op_id), "OP-123-SUFFIX");
844 }
845
846 use proptest::prelude::*;
849
850 fn non_empty_string_strategy() -> impl Strategy<Value = String> {
852 "[a-zA-Z0-9_-]{1,64}".prop_map(|s| s)
853 }
854
855 fn valid_execution_arn_strategy() -> impl Strategy<Value = String> {
857 (
858 prop_oneof![
859 Just("aws"),
860 Just("aws-cn"),
861 Just("aws-us-gov"),
862 Just("aws-iso"),
863 Just("aws-iso-b"),
864 ],
865 prop_oneof![
866 Just("us-east-1"),
867 Just("us-west-2"),
868 Just("eu-west-1"),
869 Just("cn-north-1"),
870 Just("us-gov-west-1"),
871 ],
872 "[0-9]{12}",
873 "[a-zA-Z0-9_-]{1,32}",
874 "[a-zA-Z0-9]{8,32}",
875 )
876 .prop_map(|(partition, region, account, func, exec_id)| {
877 format!(
878 "arn:{}:lambda:{}:{}:function:{}:durable:{}",
879 partition, region, account, func, exec_id
880 )
881 })
882 }
883
884 fn invalid_arn_strategy() -> impl Strategy<Value = String> {
886 prop_oneof![
887 Just("".to_string()),
889 "[a-zA-Z0-9]{10,30}".prop_map(|s| s),
891 "[a-zA-Z0-9]{5,20}".prop_map(|s| format!("arn:aws:s3:us-east-1:123456789012:{}", s)),
893 "[a-zA-Z0-9]{5,20}"
895 .prop_map(|s| format!("arn:aws:lambda:us-east-1:123456789012:function:{}", s)),
896 ]
897 }
898
899 proptest! {
900 #![proptest_config(ProptestConfig::with_cases(100))]
901
902 #[test]
908 fn prop_operation_id_validation_and_roundtrip(s in non_empty_string_strategy()) {
909 let id = OperationId::new(&s).expect("non-empty string should be valid");
911
912 let json = serde_json::to_string(&id).expect("serialization should succeed");
914 let deserialized: OperationId = serde_json::from_str(&json).expect("deserialization should succeed");
915
916 prop_assert_eq!(&id, &deserialized);
918 prop_assert_eq!(deserialized.as_str(), s.as_str());
919 }
920
921 #[test]
925 fn prop_operation_id_empty_string_rejected(_dummy in Just(())) {
926 let result = OperationId::new("");
927 prop_assert!(result.is_err());
928 let err = result.unwrap_err();
929 prop_assert_eq!(err.type_name, "OperationId");
930 prop_assert!(err.message.contains("empty"));
931 }
932
933 #[test]
936 fn prop_operation_id_from_roundtrip(s in ".*") {
937 let id = OperationId::from(s.clone());
938
939 let json = serde_json::to_string(&id).expect("serialization should succeed");
941 let deserialized: OperationId = serde_json::from_str(&json).expect("deserialization should succeed");
942
943 prop_assert_eq!(&id, &deserialized);
944 prop_assert_eq!(deserialized.as_str(), s.as_str());
945 }
946
947 #[test]
953 fn prop_execution_arn_validation_and_roundtrip(arn_str in valid_execution_arn_strategy()) {
954 let arn = ExecutionArn::new(&arn_str).expect("valid ARN should be accepted");
956
957 let json = serde_json::to_string(&arn).expect("serialization should succeed");
959 let deserialized: ExecutionArn = serde_json::from_str(&json).expect("deserialization should succeed");
960
961 prop_assert_eq!(&arn, &deserialized);
963 prop_assert_eq!(deserialized.as_str(), arn_str.as_str());
964 }
965
966 #[test]
970 fn prop_execution_arn_invalid_rejected(invalid_arn in invalid_arn_strategy()) {
971 let result = ExecutionArn::new(&invalid_arn);
972 prop_assert!(result.is_err(), "Invalid ARN '{}' should be rejected", invalid_arn);
973 }
974
975 #[test]
978 fn prop_execution_arn_from_roundtrip(s in ".*") {
979 let arn = ExecutionArn::from(s.clone());
980
981 let json = serde_json::to_string(&arn).expect("serialization should succeed");
983 let deserialized: ExecutionArn = serde_json::from_str(&json).expect("deserialization should succeed");
984
985 prop_assert_eq!(&arn, &deserialized);
986 prop_assert_eq!(deserialized.as_str(), s.as_str());
987 }
988
989 #[test]
995 fn prop_callback_id_validation_and_roundtrip(s in non_empty_string_strategy()) {
996 let id = CallbackId::new(&s).expect("non-empty string should be valid");
998
999 let json = serde_json::to_string(&id).expect("serialization should succeed");
1001 let deserialized: CallbackId = serde_json::from_str(&json).expect("deserialization should succeed");
1002
1003 prop_assert_eq!(&id, &deserialized);
1005 prop_assert_eq!(deserialized.as_str(), s.as_str());
1006 }
1007
1008 #[test]
1012 fn prop_callback_id_empty_string_rejected(_dummy in Just(())) {
1013 let result = CallbackId::new("");
1014 prop_assert!(result.is_err());
1015 let err = result.unwrap_err();
1016 prop_assert_eq!(err.type_name, "CallbackId");
1017 prop_assert!(err.message.contains("empty"));
1018 }
1019
1020 #[test]
1023 fn prop_callback_id_from_roundtrip(s in ".*") {
1024 let id = CallbackId::from(s.clone());
1025
1026 let json = serde_json::to_string(&id).expect("serialization should succeed");
1028 let deserialized: CallbackId = serde_json::from_str(&json).expect("deserialization should succeed");
1029
1030 prop_assert_eq!(&id, &deserialized);
1031 prop_assert_eq!(deserialized.as_str(), s.as_str());
1032 }
1033
1034 #[test]
1041 fn prop_operation_id_hashmap_key(s in non_empty_string_strategy(), value in any::<i32>()) {
1042 let id1 = OperationId::from(s.clone());
1043 let id2 = OperationId::from(s.clone());
1044
1045 let mut map: HashMap<OperationId, i32> = HashMap::new();
1046 map.insert(id1, value);
1047
1048 prop_assert_eq!(map.get(&id2), Some(&value));
1050 }
1051
1052 #[test]
1057 fn prop_execution_arn_hashmap_key(arn_str in valid_execution_arn_strategy(), value in any::<i32>()) {
1058 let arn1 = ExecutionArn::from(arn_str.clone());
1059 let arn2 = ExecutionArn::from(arn_str.clone());
1060
1061 let mut map: HashMap<ExecutionArn, i32> = HashMap::new();
1062 map.insert(arn1, value);
1063
1064 prop_assert_eq!(map.get(&arn2), Some(&value));
1066 }
1067
1068 #[test]
1073 fn prop_callback_id_hashmap_key(s in non_empty_string_strategy(), value in any::<i32>()) {
1074 let id1 = CallbackId::from(s.clone());
1075 let id2 = CallbackId::from(s.clone());
1076
1077 let mut map: HashMap<CallbackId, i32> = HashMap::new();
1078 map.insert(id1, value);
1079
1080 prop_assert_eq!(map.get(&id2), Some(&value));
1082 }
1083
1084 #[test]
1088 fn prop_different_keys_no_collision(
1089 s1 in non_empty_string_strategy(),
1090 s2 in non_empty_string_strategy(),
1091 value in any::<i32>()
1092 ) {
1093 prop_assume!(s1 != s2);
1094
1095 let id1 = OperationId::from(s1);
1096 let id2 = OperationId::from(s2);
1097
1098 let mut map: HashMap<OperationId, i32> = HashMap::new();
1099 map.insert(id1.clone(), value);
1100
1101 prop_assert_eq!(map.get(&id2), None);
1103 prop_assert_eq!(map.get(&id1), Some(&value));
1105 }
1106 }
1107}