#[cfg(doc)]
use syn::{parse::Parse, Generics, WhereClause, WherePredicate};
use syn::{
parse::{discouraged::Speculative as _, ParseStream},
punctuated::Punctuated,
token,
};
pub(crate) trait GenericsExt: Sized {
fn merge(&self, other: Option<&Self>) -> Self;
fn merge_where_clause(&self, c: Option<&syn::WhereClause>) -> Self;
}
impl GenericsExt for syn::Generics {
fn merge(&self, other: Option<&Self>) -> Self {
let mut gens = self.clone();
if let Some(g) = other {
gens.params.extend(g.params.clone());
gens = gens.merge_where_clause(g.where_clause.as_ref());
}
gens
}
fn merge_where_clause(&self, c: Option<&syn::WhereClause>) -> Self {
let mut gens = self.clone();
if let Some(c) = c {
gens.make_where_clause().predicates.extend(c.predicates.clone());
}
gens
}
}
pub(crate) trait WhereClauseExt: Sized {
fn parse_thrifty_opt(input: ParseStream<'_>) -> syn::Result<Option<Self>>;
}
impl WhereClauseExt for syn::WhereClause {
fn parse_thrifty_opt(input: ParseStream<'_>) -> syn::Result<Option<Self>> {
let Some(where_token) = input.parse()? else {
return Ok(None);
};
let mut predicates = Punctuated::new();
predicates.push_value(input.parse()?);
loop {
if input.is_empty()
|| input.peek(token::Brace)
|| input.peek(token::Semi)
|| input.peek(token::Colon) && !input.peek(token::PathSep)
|| input.peek(token::Eq)
{
break;
}
let ahead = input.fork();
let Ok(comma) = ahead.parse::<token::Comma>() else {
break;
};
let Ok(predicate) = ahead.parse::<syn::WherePredicate>() else {
break;
};
predicates.push_punct(comma);
predicates.push_value(predicate);
input.advance_to(&ahead);
}
Ok(Some(Self { where_token, predicates }))
}
}