playdate_bindgen/gen/
mod.rs

1#![cfg(feature = "extra-codegen")]
2use std::io::Write;
3use std::path::Path;
4use utils::toolchain::sdk::Sdk;
5use quote::ToTokens;
6use proc_macro2::TokenStream;
7
8use crate::Result;
9
10pub mod docs;
11
12
13#[allow(unused_variables)]
14pub fn engage(source: &bindgen::Bindings,
15              features: &crate::cfg::Features,
16              sdk: &Sdk,
17              root: Option<&str>)
18              -> Result<Bindings> {
19	let root_struct_name = root.unwrap_or("PlaydateAPI");
20
21	#[allow(unused_mut)]
22	let mut bindings = syn::parse_file(&source.to_string())?;
23
24	#[allow(unused_assignments)]
25	#[cfg(feature = "documentation")]
26	let docset = if features.documentation {
27		let docset_new = docs::parser::parse(sdk)?;
28		docs::gen::engage(&mut bindings, root_struct_name, &docset_new)?;
29		Some(docset_new)
30	} else {
31		None
32	};
33
34	let mut module = TokenStream::new();
35	bindings.to_tokens(&mut module);
36
37	Ok(Bindings { module,
38	              #[cfg(feature = "documentation")]
39	              docset })
40}
41
42
43/// Engaged bindings with doc-comments.
44#[derive(Debug)]
45pub struct Bindings {
46	module: TokenStream,
47
48	// for cache:
49	#[cfg(feature = "documentation")]
50	docset: Option<docs::DocsMap>,
51	// TODO: minimal cfg from parent such as formatter & rustfmt-cfg.
52}
53
54impl crate::Bindings {
55	#[cfg(feature = "documentation")]
56	pub fn docset(&self) -> Option<&docs::DocsMap> {
57		match self {
58			crate::Bindings::Bindgen(_) => None,
59			crate::Bindings::Engaged(this) => this.docset.as_ref(),
60		}
61	}
62}
63
64impl Bindings {
65	/// Write these bindings as source text to a file.
66	pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> std::io::Result<()> {
67		let file = std::fs::OpenOptions::new().write(true)
68		                                      .truncate(true)
69		                                      .create(true)
70		                                      .open(path.as_ref())?;
71		self.write(Box::new(file))?;
72		Ok(())
73	}
74
75	/// Write these bindings as source text to the given `Write`able.
76	pub fn write<'a>(&self, mut writer: Box<dyn Write + 'a>) -> std::io::Result<()> {
77		// formatting:
78		let source = self.module.to_string();
79		let output = match crate::rustfmt(None, source.clone(), None) {
80			Ok(output) => output,
81			Err(err) => {
82				println!("cargo::warning=Rustfmt error: {err}");
83
84				let output: String;
85				#[cfg(feature = "pretty-please")]
86				{
87					let tokens = &self.module;
88					output = prettyplease::unparse(&syn::parse_quote!(#tokens));
89				}
90				#[cfg(not(feature = "prettyplease"))]
91				{
92					output = source;
93				}
94				output
95			},
96		};
97
98		writer.write_all(output.as_bytes())?;
99		Ok(())
100	}
101}
102
103
104impl std::fmt::Display for Bindings {
105	#[inline(always)]
106	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107		let mut bytes = vec![];
108		self.write(Box::new(&mut bytes) as Box<dyn Write>)
109		    .expect("writing to a vec cannot fail");
110		f.write_str(std::str::from_utf8(&bytes).expect("we should only write bindings that are valid utf-8"))
111	}
112}