blob: 7bbdf46ab51858feef28d5a80e6cd9553181c1fc [file] [log] [blame]
use crate::algorithm::Printer;
use crate::iter::IterDelimited;
use crate::INDENT;
use proc_macro2::TokenStream;
use syn::{
Abi, BareFnArg, ReturnType, Type, TypeArray, TypeBareFn, TypeGroup, TypeImplTrait, TypeInfer,
TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference, TypeSlice, TypeTraitObject,
TypeTuple, Variadic,
};
impl Printer {
pub fn ty(&mut self, ty: &Type) {
match ty {
Type::Array(ty) => self.type_array(ty),
Type::BareFn(ty) => self.type_bare_fn(ty),
Type::Group(ty) => self.type_group(ty),
Type::ImplTrait(ty) => self.type_impl_trait(ty),
Type::Infer(ty) => self.type_infer(ty),
Type::Macro(ty) => self.type_macro(ty),
Type::Never(ty) => self.type_never(ty),
Type::Paren(ty) => self.type_paren(ty),
Type::Path(ty) => self.type_path(ty),
Type::Ptr(ty) => self.type_ptr(ty),
Type::Reference(ty) => self.type_reference(ty),
Type::Slice(ty) => self.type_slice(ty),
Type::TraitObject(ty) => self.type_trait_object(ty),
Type::Tuple(ty) => self.type_tuple(ty),
Type::Verbatim(ty) => self.type_verbatim(ty),
#[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
_ => unimplemented!("unknown Type"),
}
}
fn type_array(&mut self, ty: &TypeArray) {
self.word("[");
self.ty(&ty.elem);
self.word("; ");
self.expr(&ty.len);
self.word("]");
}
fn type_bare_fn(&mut self, ty: &TypeBareFn) {
if let Some(bound_lifetimes) = &ty.lifetimes {
self.bound_lifetimes(bound_lifetimes);
}
if ty.unsafety.is_some() {
self.word("unsafe ");
}
if let Some(abi) = &ty.abi {
self.abi(abi);
}
self.word("fn(");
self.cbox(INDENT);
self.zerobreak();
for bare_fn_arg in ty.inputs.iter().delimited() {
self.bare_fn_arg(&bare_fn_arg);
self.trailing_comma(bare_fn_arg.is_last && ty.variadic.is_none());
}
if let Some(variadic) = &ty.variadic {
self.variadic(variadic);
self.zerobreak();
}
self.offset(-INDENT);
self.end();
self.word(")");
self.return_type(&ty.output);
}
fn type_group(&mut self, ty: &TypeGroup) {
self.ty(&ty.elem);
}
fn type_impl_trait(&mut self, ty: &TypeImplTrait) {
self.word("impl ");
for type_param_bound in ty.bounds.iter().delimited() {
if !type_param_bound.is_first {
self.word(" + ");
}
self.type_param_bound(&type_param_bound);
}
}
fn type_infer(&mut self, ty: &TypeInfer) {
let _ = ty;
self.word("_");
}
fn type_macro(&mut self, ty: &TypeMacro) {
self.mac(&ty.mac, None);
}
fn type_never(&mut self, ty: &TypeNever) {
let _ = ty;
self.word("!");
}
fn type_paren(&mut self, ty: &TypeParen) {
self.word("(");
self.ty(&ty.elem);
self.word(")");
}
fn type_path(&mut self, ty: &TypePath) {
self.qpath(&ty.qself, &ty.path);
}
fn type_ptr(&mut self, ty: &TypePtr) {
self.word("*");
if ty.mutability.is_some() {
self.word("mut ");
} else {
self.word("const ");
}
self.ty(&ty.elem);
}
fn type_reference(&mut self, ty: &TypeReference) {
self.word("&");
if let Some(lifetime) = &ty.lifetime {
self.lifetime(lifetime);
self.nbsp();
}
if ty.mutability.is_some() {
self.word("mut ");
}
self.ty(&ty.elem);
}
fn type_slice(&mut self, ty: &TypeSlice) {
self.word("[");
self.ty(&ty.elem);
self.word("]");
}
fn type_trait_object(&mut self, ty: &TypeTraitObject) {
self.word("dyn ");
for type_param_bound in ty.bounds.iter().delimited() {
if !type_param_bound.is_first {
self.word(" + ");
}
self.type_param_bound(&type_param_bound);
}
}
fn type_tuple(&mut self, ty: &TypeTuple) {
self.word("(");
self.cbox(INDENT);
self.zerobreak();
for elem in ty.elems.iter().delimited() {
self.ty(&elem);
if ty.elems.len() == 1 {
self.word(",");
self.zerobreak();
} else {
self.trailing_comma(elem.is_last);
}
}
self.offset(-INDENT);
self.end();
self.word(")");
}
#[cfg(not(feature = "verbatim"))]
fn type_verbatim(&mut self, ty: &TokenStream) {
if ty.to_string() == "..." {
self.word("...");
} else {
unimplemented!("Type::Verbatim `{}`", ty);
}
}
#[cfg(feature = "verbatim")]
fn type_verbatim(&mut self, tokens: &TokenStream) {
use syn::parse::{Parse, ParseStream, Result};
use syn::{token, ExprBlock, Lit};
enum TypeVerbatim {
Lit(Lit),
Block(ExprBlock),
}
impl Parse for TypeVerbatim {
fn parse(input: ParseStream) -> Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(Lit) {
input.parse().map(TypeVerbatim::Lit)
} else if lookahead.peek(token::Brace) {
input.parse().map(TypeVerbatim::Block)
} else {
Err(lookahead.error())
}
}
}
let ty: TypeVerbatim = match syn::parse2(tokens.clone()) {
Ok(ty) => ty,
Err(_) => unimplemented!("Type::Verbatim `{}`", tokens),
};
match ty {
TypeVerbatim::Lit(lit) => {
self.lit(&lit);
}
TypeVerbatim::Block(block) => {
self.expr_block(&block);
}
}
}
pub fn return_type(&mut self, ty: &ReturnType) {
match ty {
ReturnType::Default => {}
ReturnType::Type(_arrow, ty) => {
self.word(" -> ");
self.ty(ty);
}
}
}
fn bare_fn_arg(&mut self, bare_fn_arg: &BareFnArg) {
self.outer_attrs(&bare_fn_arg.attrs);
if let Some((name, _colon)) = &bare_fn_arg.name {
self.ident(name);
self.word(": ");
}
self.ty(&bare_fn_arg.ty);
}
fn variadic(&mut self, variadic: &Variadic) {
self.outer_attrs(&variadic.attrs);
self.word("...");
}
pub fn abi(&mut self, abi: &Abi) {
self.word("extern ");
if let Some(name) = &abi.name {
self.lit_str(name);
self.nbsp();
}
}
}