futhark_bindgen/generate/
mod.rs1use crate::*;
2
3mod ocaml;
4mod rust;
5
6pub use ocaml::OCaml;
7pub use rust::Rust;
8
9pub(crate) fn first_uppercase(s: &str) -> String {
10 let mut s = s.to_string();
11 if let Some(r) = s.get_mut(0..1) {
12 r.make_ascii_uppercase();
13 }
14 s
15}
16
17pub(crate) fn convert_struct_name(s: &str) -> &str {
18 s.strip_prefix("struct")
19 .unwrap()
20 .strip_suffix('*')
21 .unwrap()
22 .strip_prefix(|x: char| x.is_ascii_whitespace())
23 .unwrap()
24 .strip_suffix(|x: char| x.is_ascii_whitespace())
25 .unwrap()
26}
27
28pub struct Config {
30 pub output_path: std::path::PathBuf,
32
33 pub output_file: std::fs::File,
35}
36
37impl Config {
38 pub fn new(output: impl AsRef<std::path::Path>) -> Result<Config, Error> {
40 Ok(Config {
41 output_path: output.as_ref().to_path_buf(),
42 output_file: std::fs::File::create(output)?,
43 })
44 }
45}
46
47pub trait Generate {
48 fn generate(&mut self, pkg: &Package, config: &mut Config) -> Result<(), Error> {
50 self.bindings(pkg, config)?;
51 for (name, ty) in &pkg.manifest.types {
52 match ty {
53 manifest::Type::Array(ty) => {
54 self.array_type(pkg, config, name, ty)?;
55 }
56 manifest::Type::Opaque(ty) => {
57 self.opaque_type(pkg, config, name, ty)?;
58 }
59 }
60 }
61
62 for (name, entry) in &pkg.manifest.entry_points {
63 self.entry(pkg, config, name, entry)?;
64 }
65 self.format(&config.output_path)?;
66 Ok(())
67 }
68
69 fn bindings(&mut self, _pkg: &Package, _config: &mut Config) -> Result<(), Error>;
71
72 fn array_type(
74 &mut self,
75 pkg: &Package,
76 config: &mut Config,
77 name: &str,
78 ty: &manifest::ArrayType,
79 ) -> Result<(), Error>;
80
81 fn opaque_type(
83 &mut self,
84 pkg: &Package,
85 config: &mut Config,
86 name: &str,
87 ty: &manifest::OpaqueType,
88 ) -> Result<(), Error>;
89
90 fn entry(
92 &mut self,
93 pkg: &Package,
94 config: &mut Config,
95 name: &str,
96 entry: &manifest::Entry,
97 ) -> Result<(), Error>;
98
99 fn format(&mut self, _output: &std::path::Path) -> Result<(), Error> {
101 Ok(())
102 }
103}
104
105fn rust() -> Box<impl Generate> {
106 Box::<Rust>::default()
107}
108
109fn ocaml(config: &Config) -> Box<impl Generate> {
110 Box::new(OCaml::new(config).unwrap())
111}
112
113impl Config {
114 pub fn detect(&self) -> Option<Box<dyn Generate>> {
116 match self
117 .output_path
118 .extension()
119 .map(|x| x.to_str().expect("Invalid extension"))
120 {
121 Some("rs") => Some(rust()),
122 Some("ml") => Some(ocaml(self)),
123 _ => None,
124 }
125 }
126}