use quote::ToTokens;
use syn::{GenericArgument, Path, PathArguments, PathSegment};
trait NodeMatch {
fn match_prefix(&self, other: &Self) -> bool;
}
impl NodeMatch for GenericArgument {
fn match_prefix(&self, other: &Self) -> bool {
if let GenericArgument::Lifetime(_) = self {
matches!(other, GenericArgument::Lifetime(_))
} else {
self == other
}
}
}
impl NodeMatch for PathSegment {
fn match_prefix(&self, seg_pat: &PathSegment) -> bool {
self.ident == seg_pat.ident && match &seg_pat.arguments {
PathArguments::None =>
true, PathArguments::AngleBracketed(ab_pat) => {
if let PathArguments::AngleBracketed(ab) = &self.arguments {
ab.args.len() == ab_pat.args.len() &&
ab.args.iter().zip(&ab_pat.args).all(|(a, b)| a.match_prefix(b))
} else {
false
}
}
PathArguments::Parenthesized(p_pat) => {
if let PathArguments::Parenthesized(p) = &self.arguments {
p == p_pat
} else {
false
}
}
}
}
}
pub(crate) fn pathname<T: ToTokens>(path: &T) -> String {
path.to_token_stream().to_string()
.replace(" :: ", "::")
.replace(" <", "<")
.replace("< ", "<")
.replace(" >", ">")
.replace("> ", ">")
.replace("& ", "&")
.replace(", ", ",")
.replace(") ", ")")
.replace(" ;", ";")
.replace("; ", ";")
}
pub(crate) fn path_prefix_len(prefix: &Path, full_path: &Path) -> Option<usize> {
let prefix_len = prefix.segments.len();
if full_path.leading_colon == prefix.leading_colon && full_path.segments.len() >= prefix_len {
for (seg_full, seg_prefix) in full_path.segments.iter().zip(&prefix.segments) {
if !seg_full.match_prefix(seg_prefix) {
return None;
}
}
return Some(prefix_len)
}
None
}
pub(crate) fn replace_str(string: &str, pat: &str, repl: &str) -> Option<String> {
if string.contains(pat) {
Some(string.replace(pat, repl))
} else {
None
}
}