`parse_list_inner`'s separation from `parse_list` simplifies error handling by allowing subprocedures to return `String` errors.
(
s: &'a str,
is_element_type_list: bool,
mut make_null: impl FnMut() -> T,
mut gen_elem: impl FnMut(Cow<'a, str>) -> Result<T, E>,
)
| 1074 | // `parse_list_inner`'s separation from `parse_list` simplifies error handling |
| 1075 | // by allowing subprocedures to return `String` errors. |
| 1076 | fn parse_list_inner<'a, T, E>( |
| 1077 | s: &'a str, |
| 1078 | is_element_type_list: bool, |
| 1079 | mut make_null: impl FnMut() -> T, |
| 1080 | mut gen_elem: impl FnMut(Cow<'a, str>) -> Result<T, E>, |
| 1081 | ) -> Result<Vec<T>, String> |
| 1082 | where |
| 1083 | E: ToString, |
| 1084 | { |
| 1085 | let mut elems = vec![]; |
| 1086 | let buf = &mut LexBuf::new(s); |
| 1087 | |
| 1088 | // Consume opening paren. |
| 1089 | if !buf.consume('{') { |
| 1090 | bail!( |
| 1091 | "expected '{{', found {}", |
| 1092 | match buf.next() { |
| 1093 | Some(c) => format!("{}", c), |
| 1094 | None => "empty string".to_string(), |
| 1095 | } |
| 1096 | ) |
| 1097 | } |
| 1098 | |
| 1099 | // Simplifies calls to `gen_elem` by handling errors |
| 1100 | let mut generated = |elem| gen_elem(elem).map_err(|e| e.to_string()); |
| 1101 | let is_special_char = |c| matches!(c, '{' | '}' | ',' | '\\' | '"'); |
| 1102 | let is_end_of_literal = |c| matches!(c, ',' | '}'); |
| 1103 | |
| 1104 | // Consume elements. |
| 1105 | loop { |
| 1106 | buf.take_while(|ch| ch.is_ascii_whitespace()); |
| 1107 | // Check for terminals. |
| 1108 | match buf.next() { |
| 1109 | Some('}') => { |
| 1110 | break; |
| 1111 | } |
| 1112 | _ if elems.len() == 0 => { |
| 1113 | buf.prev(); |
| 1114 | } |
| 1115 | Some(',') => {} |
| 1116 | Some(c) => bail!("expected ',' or '}}', got '{}'", c), |
| 1117 | None => bail!("unexpected end of input"), |
| 1118 | } |
| 1119 | |
| 1120 | buf.take_while(|ch| ch.is_ascii_whitespace()); |
| 1121 | // Get elements. |
| 1122 | let elem = match buf.peek() { |
| 1123 | Some('"') => generated(lex_quoted_element(buf)?)?, |
| 1124 | Some('{') => { |
| 1125 | if !is_element_type_list { |
| 1126 | bail!( |
| 1127 | "unescaped '{{' at beginning of element; perhaps you \ |
| 1128 | want a nested list, e.g. '{{a}}'::text list list" |
| 1129 | ) |
| 1130 | } |
| 1131 | generated(lex_embedded_element(buf)?)? |
| 1132 | } |
| 1133 | Some(_) => match lex_unquoted_element(buf, is_special_char, is_end_of_literal)? { |
no test coverage detected