aranya_capi_codegen/syntax/
util.rs1use std::fmt;
2
3use proc_macro2::TokenStream;
4use quote::{quote, ToTokens};
5use syn::{GenericArgument, Ident, Path, PathArguments, Type, TypePath};
6
7pub struct Trimmed<'a, T>(pub &'a T);
9
10impl<'a> fmt::Display for Trimmed<'a, TypePath> {
11 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
12 if self.0.qself.is_some() {
13 write!(f, "<...>::")?;
15 }
16 write_path(f, &self.0.path)
17 }
18}
19
20impl<'a> fmt::Display for Trimmed<'a, Path> {
21 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22 write_path(f, self.0)
23 }
24}
25
26impl<'a> fmt::Display for Trimmed<'a, Ident> {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 write_path(f, &self.0.clone().into())
29 }
30}
31
32fn write_path(f: &mut fmt::Formatter<'_>, path: &Path) -> fmt::Result {
33 write!(f, "\"")?;
34 if path.leading_colon.is_some() {
35 write!(f, "::")?;
36 }
37 for pair in path.segments.pairs() {
38 let seg = pair.value();
39 write!(f, "{}", seg.ident)?;
40 match &seg.arguments {
41 PathArguments::None => {}
42 PathArguments::AngleBracketed(args) => {
43 write!(f, "<")?;
44 for arg in &args.args {
45 match &arg {
46 GenericArgument::Type(ty) => write_type(f, ty)?,
47 GenericArgument::Lifetime(lt) => write!(f, "'{}", lt.ident)?,
48 _ => write!(f, "???")?,
49 }
50 }
51 write!(f, ">")?;
52 }
53 PathArguments::Parenthesized(_) => {
54 unreachable!("Parenthesized")
55 }
56 }
57 if pair.punct().is_some() {
58 write!(f, "::")?;
59 }
60 }
61 write!(f, "\"")
62}
63
64fn write_type(f: &mut fmt::Formatter<'_>, ty: &Type) -> fmt::Result {
65 let mut code = quote!(const _: #ty = ();).to_string();
66 if let Ok(file) = syn::parse_file(&code) {
67 code = prettyplease::unparse(&file);
68 }
69 let code = code
70 .trim()
71 .strip_prefix("const _: ")
72 .unwrap_or(&code)
73 .strip_suffix(" = ();")
74 .unwrap_or(&code);
75
76 let mut space = false;
77 for c in code.chars() {
78 if c == '\n' || c == '\t' {
79 continue;
80 }
81 if c.is_whitespace() {
82 if !space {
83 write!(f, " ")?;
84 space = true;
85 }
86 } else {
87 write!(f, "{c}")?;
88 space = false;
89 }
90 }
91 Ok(())
92}
93
94#[allow(dead_code)] pub(super) struct Quote<'a, T>(pub &'a T);
96
97impl<'a, T: ToTokens> fmt::Display for Quote<'a, T> {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 let v = &self.0;
100 write!(f, "\"{}\"", quote!(#v))
101 }
102}
103
104pub(super) struct TokensOrDefault<'a, T>(pub &'a Option<T>);
106
107impl<'a, T> ToTokens for TokensOrDefault<'a, T>
108where
109 T: ToTokens + Default,
110{
111 fn to_tokens(&self, tokens: &mut TokenStream) {
112 match self.0 {
113 Some(t) => t.to_tokens(tokens),
114 None => T::default().to_tokens(tokens),
115 }
116 }
117}