aboutsummaryrefslogtreecommitdiff
path: root/src/matchers/tuple_matcher.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/matchers/tuple_matcher.rs')
-rw-r--r--src/matchers/tuple_matcher.rs207
1 files changed, 207 insertions, 0 deletions
diff --git a/src/matchers/tuple_matcher.rs b/src/matchers/tuple_matcher.rs
new file mode 100644
index 0000000..a2e325b
--- /dev/null
+++ b/src/matchers/tuple_matcher.rs
@@ -0,0 +1,207 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// There are no visible documentation elements in this module; the declarative
+// macro is documented at the top level.
+#![doc(hidden)]
+
+/// Functions for use only by the declarative macros in this module.
+///
+/// **For internal use only. API stablility is not guaranteed!**
+#[doc(hidden)]
+pub mod internal {
+ use crate::matcher::{Matcher, MatcherResult};
+ use std::fmt::{Debug, Write};
+
+ /// Replaces the first expression with the second at compile time.
+ ///
+ /// This is used below in repetition sequences where the output must only
+ /// include the same expression repeated the same number of times as the
+ /// macro input.
+ ///
+ /// **For internal use only. API stablility is not guaranteed!**
+ #[doc(hidden)]
+ macro_rules! replace_expr {
+ ($_ignored:tt, $replacement:expr) => {
+ $replacement
+ };
+ }
+
+ // This implementation is provided for completeness, but is completely trivial.
+ // The only actual value which can be supplied is (), which must match.
+ impl Matcher for () {
+ type ActualT = ();
+
+ fn matches(&self, _: &Self::ActualT) -> MatcherResult {
+ MatcherResult::Match
+ }
+
+ fn describe(&self, matcher_result: MatcherResult) -> String {
+ match matcher_result {
+ MatcherResult::Match => "is the empty tuple".into(),
+ MatcherResult::NoMatch => "is not the empty tuple".into(),
+ }
+ }
+ }
+
+ /// Generates a tuple matcher for tuples of a specific length.
+ ///
+ /// **For internal use only. API stablility is not guaranteed!**
+ #[doc(hidden)]
+ macro_rules! tuple_matcher_n {
+ ($([$field_number:tt, $matcher_type:ident, $field_type:ident]),*) => {
+ impl<$($field_type: Debug, $matcher_type: Matcher<ActualT = $field_type>),*>
+ Matcher for ($($matcher_type,)*)
+ {
+ type ActualT = ($($field_type,)*);
+
+ fn matches(&self, actual: &($($field_type,)*)) -> MatcherResult {
+ $(match self.$field_number.matches(&actual.$field_number) {
+ MatcherResult::Match => {},
+ MatcherResult::NoMatch => {
+ return MatcherResult::NoMatch;
+ }
+ })*
+ MatcherResult::Match
+ }
+
+ fn explain_match(&self, actual: &($($field_type,)*)) -> String {
+ let mut explanation = format!("which {}", self.describe(self.matches(actual)));
+ $(match self.$field_number.matches(&actual.$field_number) {
+ MatcherResult::Match => {},
+ MatcherResult::NoMatch => {
+ writeln!(
+ &mut explanation,
+ concat!("Element #", $field_number, " is {:?}, {}"),
+ actual.$field_number,
+ self.$field_number.explain_match(&actual.$field_number)
+ ).unwrap();
+ }
+ })*
+ (explanation)
+ }
+
+ fn describe(&self, matcher_result: MatcherResult) -> String {
+ match matcher_result {
+ MatcherResult::Match => {
+ format!(
+ concat!(
+ "is a tuple whose values respectively match:\n",
+ $(replace_expr!($field_number, " {},\n")),*
+ ),
+ $(self.$field_number.describe(matcher_result)),*
+ )
+ }
+ MatcherResult::NoMatch => {
+ format!(
+ concat!(
+ "is a tuple whose values do not respectively match:\n",
+ $(replace_expr!($field_number, " {},\n")),*
+ ),
+ $(self.$field_number.describe(MatcherResult::Match)),*
+ )
+ }
+ }
+ }
+ }
+ };
+ }
+
+ tuple_matcher_n!([0, I0, T0]);
+
+ tuple_matcher_n!([0, I0, T0], [1, I1, T1]);
+
+ tuple_matcher_n!([0, I0, T0], [1, I1, T1], [2, I2, T2]);
+
+ tuple_matcher_n!([0, I0, T0], [1, I1, T1], [2, I2, T2], [3, I3, T3]);
+
+ tuple_matcher_n!([0, I0, T0], [1, I1, T1], [2, I2, T2], [3, I3, T3], [4, I4, T4]);
+
+ tuple_matcher_n!([0, I0, T0], [1, I1, T1], [2, I2, T2], [3, I3, T3], [4, I4, T4], [5, I5, T5]);
+
+ tuple_matcher_n!(
+ [0, I0, T0],
+ [1, I1, T1],
+ [2, I2, T2],
+ [3, I3, T3],
+ [4, I4, T4],
+ [5, I5, T5],
+ [6, I6, T6]
+ );
+
+ tuple_matcher_n!(
+ [0, I0, T0],
+ [1, I1, T1],
+ [2, I2, T2],
+ [3, I3, T3],
+ [4, I4, T4],
+ [5, I5, T5],
+ [6, I6, T6],
+ [7, I7, T7]
+ );
+
+ tuple_matcher_n!(
+ [0, I0, T0],
+ [1, I1, T1],
+ [2, I2, T2],
+ [3, I3, T3],
+ [4, I4, T4],
+ [5, I5, T5],
+ [6, I6, T6],
+ [7, I7, T7],
+ [8, I8, T8]
+ );
+
+ tuple_matcher_n!(
+ [0, I0, T0],
+ [1, I1, T1],
+ [2, I2, T2],
+ [3, I3, T3],
+ [4, I4, T4],
+ [5, I5, T5],
+ [6, I6, T6],
+ [7, I7, T7],
+ [8, I8, T8],
+ [9, I9, T9]
+ );
+
+ tuple_matcher_n!(
+ [0, I0, T0],
+ [1, I1, T1],
+ [2, I2, T2],
+ [3, I3, T3],
+ [4, I4, T4],
+ [5, I5, T5],
+ [6, I6, T6],
+ [7, I7, T7],
+ [8, I8, T8],
+ [9, I9, T9],
+ [10, I10, T10]
+ );
+
+ tuple_matcher_n!(
+ [0, I0, T0],
+ [1, I1, T1],
+ [2, I2, T2],
+ [3, I3, T3],
+ [4, I4, T4],
+ [5, I5, T5],
+ [6, I6, T6],
+ [7, I7, T7],
+ [8, I8, T8],
+ [9, I9, T9],
+ [10, I10, T10],
+ [11, I11, T11]
+ );
+}