Finds an exact match based on the arguments, or, if no exact match, finds the best match available. Patterned after [PostgreSQL's type conversion matching algorithm][pgparser]. [pgparser]: https://www.postgresql.org/docs/current/typeconv-func.html
(
ecx: &ExprContext,
types: &[CoercibleScalarType],
impls: Vec<&'a FuncImpl<R>>,
)
| 1082 | /// |
| 1083 | /// [pgparser]: https://www.postgresql.org/docs/current/typeconv-func.html |
| 1084 | fn find_match<'a, R: std::fmt::Debug>( |
| 1085 | ecx: &ExprContext, |
| 1086 | types: &[CoercibleScalarType], |
| 1087 | impls: Vec<&'a FuncImpl<R>>, |
| 1088 | ) -> Result<&'a FuncImpl<R>, usize> { |
| 1089 | let all_types_known = types.iter().all(|t| t.is_coerced()); |
| 1090 | |
| 1091 | // Check for exact match. |
| 1092 | if all_types_known { |
| 1093 | let known_types: Vec<_> = types.iter().filter_map(|t| t.as_coerced()).collect(); |
| 1094 | let matching_impls: Vec<&FuncImpl<_>> = impls |
| 1095 | .iter() |
| 1096 | .filter(|i| i.params.exact_match(&known_types)) |
| 1097 | .cloned() |
| 1098 | .collect(); |
| 1099 | |
| 1100 | if matching_impls.len() == 1 { |
| 1101 | return Ok(matching_impls[0]); |
| 1102 | } |
| 1103 | } |
| 1104 | |
| 1105 | // No exact match. Apply PostgreSQL's best match algorithm. Generate |
| 1106 | // candidates by assessing their compatibility with each implementation's |
| 1107 | // parameters. |
| 1108 | let mut candidates: Vec<Candidate<_>> = Vec::new(); |
| 1109 | macro_rules! maybe_get_last_candidate { |
| 1110 | () => { |
| 1111 | if candidates.len() == 1 { |
| 1112 | return Ok(&candidates[0].fimpl); |
| 1113 | } |
| 1114 | }; |
| 1115 | } |
| 1116 | let mut max_exact_matches = 0; |
| 1117 | |
| 1118 | for fimpl in impls { |
| 1119 | let mut exact_matches = 0; |
| 1120 | let mut preferred_types = 0; |
| 1121 | let mut near_matches = 0; |
| 1122 | |
| 1123 | for (i, arg_type) in types.iter().enumerate() { |
| 1124 | let param_type = &fimpl.params[i]; |
| 1125 | |
| 1126 | match arg_type { |
| 1127 | CoercibleScalarType::Coerced(arg_type) => { |
| 1128 | if param_type == arg_type { |
| 1129 | exact_matches += 1; |
| 1130 | } |
| 1131 | if param_type.is_preferred_by(arg_type) { |
| 1132 | preferred_types += 1; |
| 1133 | } |
| 1134 | if param_type.is_near_match(arg_type) { |
| 1135 | near_matches += 1; |
| 1136 | } |
| 1137 | } |
| 1138 | CoercibleScalarType::Record(_) | CoercibleScalarType::Uncoerced => { |
| 1139 | if param_type.prefers_self() { |
| 1140 | preferred_types += 1; |
| 1141 | } |
no test coverage detected