use syn::{BinOp, Expr};
use super::first_generic_type;
pub(super) fn flatten_and(cond: &Expr) -> Vec<&Expr> {
pub(super) fn walk<'a>(e: &'a Expr, out: &mut Vec<&'a Expr>) {
if let Expr::Binary(b) = e
&& matches!(b.op, BinOp::And(_))
{
walk(&b.left, out);
walk(&b.right, out);
} else {
out.push(e);
}
}
let mut out = Vec::new();
walk(cond, &mut out);
out
}
pub(super) fn from_str_root(e: &Expr) -> Option<&syn::ExprCall> {
from_str_chain(e, false)
}
fn maps_only_the_error(method: &syn::Ident) -> bool {
method == "map_err" || method == "context" || method == "with_context"
}
fn from_str_chain(e: &Expr, unwrapped: bool) -> Option<&syn::ExprCall> {
match e {
Expr::Call(c) => {
let Expr::Path(p) = &*c.func else { return None };
let seg = p.path.segments.last()?;
if seg.ident != "from_str" || first_generic_type(seg).is_some() {
return None;
}
Some(c)
}
Expr::Try(t) => from_str_chain(&t.expr, true),
Expr::Paren(p) => from_str_chain(&p.expr, unwrapped),
Expr::Group(g) => from_str_chain(&g.expr, unwrapped),
Expr::MethodCall(m) if m.method == "unwrap" || m.method == "expect" => {
from_str_chain(&m.receiver, true)
}
Expr::MethodCall(m) if unwrapped && maps_only_the_error(&m.method) => {
from_str_chain(&m.receiver, unwrapped)
}
_ => None,
}
}
pub(super) fn unparen(expr: &Expr) -> &Expr {
match expr {
Expr::Paren(p) => unparen(&p.expr),
Expr::Group(g) => unparen(&g.expr),
other => other,
}
}
pub(super) fn qualified_method_ref(p: &syn::ExprPath) -> Vec<String> {
let owner = match p.qself.as_ref().map(|q| &*q.ty) {
Some(syn::Type::Path(tp)) => tp
.path
.segments
.last()
.map_or_else(|| "Vec".to_string(), |s| s.ident.to_string()),
Some(syn::Type::Slice(_)) => "Vec".to_string(),
_ => "str".to_string(),
};
vec![owner, p.path.segments[0].ident.to_string()]
}