diff --git a/src/lib.rs b/src/lib.rs index 9fc143b..8091aa4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -815,6 +815,18 @@ impl CtOption { pub fn into_option(self) -> Option { self.into() } + + /// Take a `CtOption` and merge it with a `CtOption` to produce a + /// `CtOption<(T, U)>`. + /// + /// The result contains each option's value, and is `Some` if and only if each + /// of the options is `Some`. + pub fn merge(self, other: CtOption) -> CtOption<(T, U)> { + CtOption { + value: (self.value, other.value), + is_some: self.is_some & other.is_some, + } + } } impl ConditionallySelectable for CtOption { diff --git a/tests/mod.rs b/tests/mod.rs index 888b9d0..8df800a 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -300,6 +300,12 @@ fn test_ctoption() { assert!(CtOption::new(1, Choice::from(1)).ct_eq(&CtOption::new(2, Choice::from(1))).unwrap_u8() == 0); assert!(CtOption::new(1, Choice::from(1)).ct_eq(&CtOption::new(1, Choice::from(1))).unwrap_u8() == 1); assert!(CtOption::new(1, Choice::from(1)).ct_eq(&CtOption::new(1, Choice::from(1))).unwrap_u8() == 1); + + // Test merging + assert!(CtOption::new(1u8, Choice::from(0)).merge(CtOption::new(0u32, Choice::from(0))).into_option().is_none()); + assert!(CtOption::new(1u8, Choice::from(1)).merge(CtOption::new(0u32, Choice::from(0))).into_option().is_none()); + assert!(CtOption::new(1u8, Choice::from(0)).merge(CtOption::new(0u32, Choice::from(1))).into_option().is_none()); + assert_eq!(CtOption::new(1u8, Choice::from(1)).merge(CtOption::new(0u32, Choice::from(1))).into_option(), Some((1u8, 0u32))); } #[test]