// match tuples and unused parentheses let target_is_tuple = opt_opening_paren.parse_next(i)?; if target_is_tuple { let (singleton, mut targets) =
collect_targets(i, ')', |i: &mut _| Self::unnamed(i, s))?; if singleton { return Ok(targets.pop().unwrap());
} return Ok(Self::Tuple(
Vec::new(),
only_one_rest_pattern(targets, false, "tuple")?,
));
} let target_is_array = opt_opening_bracket.parse_next(i)?; if target_is_array { let (singleton, mut targets) =
collect_targets(i, ']', |i: &mut _| Self::unnamed(i, s))?; if singleton { return Ok(targets.pop().unwrap());
} return Ok(Self::Array(
Vec::new(),
only_one_rest_pattern(targets, true, "array")?,
));
}
let path = path_or_identifier.try_map(|v| match v {
PathOrIdentifier::Path(v) => Ok(v),
PathOrIdentifier::Identifier(v) => Err(v),
});
// match structs let path = opt(path).parse_next(i)?; iflet Some(path) = path { let i_before_matching_with = *i; let _ = opt(ws(keyword("with"))).parse_next(i)?;
let is_unnamed_struct = opt_opening_paren.parse_next(i)?; if is_unnamed_struct { let (_, targets) = collect_targets(i, ')', |i: &mut _| Self::unnamed(i, s))?; return Ok(Self::Tuple(
path,
only_one_rest_pattern(targets, false, "struct")?,
));
}
let is_named_struct = opt_opening_brace.parse_next(i)?; if is_named_struct { let (_, targets) = collect_targets(i, '}', |i: &mut _| Self::named(i, s))?; return Ok(Self::Struct(path, targets));
}
// neither literal nor struct nor path let i_before_identifier = *i; let name = identifier.parse_next(i)?; let target = match name { "_" => Self::Placeholder(WithSpan::new((), i_before_identifier)),
_ => verify_name(i_before_identifier, name)?,
};
Ok(target)
}
fn named(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, (&'a str, Self)> { let start = *i; let rest = opt(Self::rest.with_taken()).parse_next(i)?; iflet Some(rest) = rest { let chr = peek(ws(opt(one_of([',', ':'])))).parse_next(i)?; iflet Some(chr) = chr { return Err(winnow::error::ErrMode::Cut(ErrorContext::new(
format!( "unexpected `{chr}` character after `..`\n\
note that in a named struct, `..` must come last to ignore other members"
),
*i,
)));
} iflet Target::Rest(ref s) = rest.0 { if s.inner.is_some() { return Err(winnow::error::ErrMode::Cut(ErrorContext::new( "`@ ..` cannot be used in struct",
s.span,
)));
}
} return Ok((rest.1, rest.0));
}
if src == "_" {
*i = start; return Err(winnow::error::ErrMode::Cut(ErrorContext::new( "cannot use placeholder `_` as source in named struct",
*i,
)));
}
let target = match target {
Some(target) => target,
None => verify_name(start, src)?,
};
Ok((src, target))
}
fn verify_name<'a>(
input: &'a str,
name: &'a str,
) -> Result<Target<'a>, winnow::error::ErrMode<ErrorContext<'a>>> { if is_rust_keyword(name) {
Err(winnow::error::ErrMode::Cut(ErrorContext::new(
format!("cannot use `{name}` as a name: it is a rust keyword"),
input,
)))
} elseif name.starts_with("__askama") {
Err(winnow::error::ErrMode::Cut(ErrorContext::new(
format!("cannot use `{name}` as a name: it is reserved for `askama`"),
input,
)))
} else {
Ok(Target::Name(name))
}
}
let has_end = opt_end.parse_next(i)?; if has_end { return Ok((false, Vec::new()));
}
let targets = opt(separated(1.., one, ws(',')).map(|v: Vec<_>| v)).parse_next(i)?; let Some(targets) = targets else { return Err(winnow::error::ErrMode::Cut(ErrorContext::new( "expected comma separated list of members",
*i,
)));
};
let (has_comma, has_end) = (opt_comma, opt_end).parse_next(i)?; if !has_end { let msg = match has_comma { true => format!("expected member, or `{delim}` as terminator"), false => format!("expected `,` for more members, or `{delim}` as terminator"),
}; return Err(winnow::error::ErrMode::Cut(ErrorContext::new(msg, *i)));
}
for target in &targets { iflet Target::Rest(s) = target { if !allow_named_rest && s.inner.is_some() { return Err(winnow::error::ErrMode::Cut(ErrorContext::new( "`@ ..` is only allowed in slice patterns",
s.span,
)));
} if found_rest { return Err(winnow::error::ErrMode::Cut(ErrorContext::new(
format!("`..` can only be used once per {type_kind} pattern"),
s.span,
)));
}
found_rest = true;
}
}
Ok(targets)
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-08-25)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.