1use std::{collections::BTreeMap, fmt, path::PathBuf, str::FromStr};
2
3use serde::{Deserialize, Serialize};
4use toml::Value as TomlValue;
5
6use crate::error::Error;
7
8#[non_exhaustive]
10#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
11#[serde(rename_all = "lowercase")]
12pub enum OutputLanguage {
13 Poly,
15 Html,
17 Rust,
19 AssemblyScript,
21 TinyGo,
23 Go,
25 Python,
27 Clang,
29}
30
31impl std::str::FromStr for OutputLanguage {
32 type Err = Error;
33
34 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
35 match s.to_ascii_lowercase().as_str() {
36 "poly" => Ok(OutputLanguage::Poly),
37 "html" => Ok(OutputLanguage::Html),
38 "rust" => Ok(OutputLanguage::Rust),
39 "assemblyscript" => Ok(OutputLanguage::AssemblyScript),
40 "tinygo" => Ok(OutputLanguage::TinyGo),
41 "go" => Ok(OutputLanguage::Go),
42 "python" => Ok(OutputLanguage::Python),
43 "c++" | "clang" => Ok(OutputLanguage::Clang),
44 _ => Err(Error::UnsupportedLanguage(s.to_string())),
45 }
46 }
47}
48
49impl fmt::Display for OutputLanguage {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 write!(
52 f,
53 "{}",
54 match self {
55 OutputLanguage::Poly => "Poly",
56 OutputLanguage::Html => "Html",
57 OutputLanguage::Rust => "Rust",
58 OutputLanguage::AssemblyScript => "AssemblyScript",
59 OutputLanguage::TinyGo => "TinyGo",
60 OutputLanguage::Go => "Go",
61 OutputLanguage::Python => "Python",
62 OutputLanguage::Clang => "Clang",
63 }
64 )
65 }
66}
67
68impl OutputLanguage {
69 pub fn extension(&self) -> &'static str {
71 match self {
72 OutputLanguage::Rust => "rs",
73 OutputLanguage::TinyGo | OutputLanguage::Go => "go",
74 OutputLanguage::AssemblyScript => "rs",
75 OutputLanguage::Python => "rs",
76 OutputLanguage::Poly => "",
77 OutputLanguage::Html => "html",
78 OutputLanguage::Clang => "c",
79 }
80 }
81}
82
83#[derive(Debug, Deserialize, Serialize)]
84pub struct CodegenConfig {
85 #[serde(default)]
87 pub models: Vec<ModelSource>,
88
89 #[serde(default)]
92 pub output_languages: Vec<OutputLanguage>,
93
94 #[serde(flatten)]
96 pub languages: BTreeMap<OutputLanguage, LanguageConfig>,
97
98 #[serde(default)]
103 pub base_dir: PathBuf,
104}
105
106#[derive(Debug, Deserialize, Serialize)]
111#[serde(untagged)]
112pub enum ModelSource {
113 Url {
114 url: String,
115 #[serde(default)]
116 files: Vec<String>,
117 },
118 Path {
119 path: PathBuf,
120 #[serde(default)]
121 files: Vec<String>,
122 },
123}
124
125pub enum ModelSourceKind {
126 Url(String),
127 Path(PathBuf),
128}
129
130impl FromStr for ModelSource {
131 type Err = std::convert::Infallible;
132
133 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
134 Ok(if s.starts_with("https:") || s.starts_with("http:") {
135 ModelSource::Url {
136 url: s.to_string(),
137 files: Vec::default(),
138 }
139 } else {
140 ModelSource::Path { path: s.into(), files: Vec::default() }
141 })
142 }
143}
144
145impl ModelSource {
146 pub fn from_file<P: Into<std::path::PathBuf>>(path: P) -> ModelSource {
148 ModelSource::Path { path: path.into(), files: Vec::default() }
149 }
150}
151
152impl fmt::Display for ModelSource {
153 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154 write!(
155 f,
156 "{}",
157 match self {
158 ModelSource::Url { url, files: _ } => format!("url({url})"),
159 ModelSource::Path { path, files: _ } => format!("path({})", path.display()),
160 }
161 )
162 }
163}
164
165#[derive(Debug, Default, Deserialize, Serialize)]
166pub struct LanguageConfig {
167 #[serde(default)]
170 pub templates: Option<PathBuf>,
171
172 pub output_dir: PathBuf,
175
176 #[serde(default)]
178 pub parameters: BTreeMap<String, TomlValue>,
179
180 #[serde(default)]
186 pub formatter: Vec<String>,
187
188 #[serde(default)]
190 pub files: Vec<OutputFile>,
191}
192
193#[derive(Debug, Default, Deserialize, Serialize)]
195pub struct OutputFile {
196 pub path: PathBuf,
198
199 #[serde(default)]
202 pub hbs: Option<String>,
203
204 #[serde(default)]
206 pub create_only: bool,
207
208 #[serde(default)]
210 pub namespace: Option<String>,
211
212 #[serde(flatten)]
214 pub params: BTreeMap<String, TomlValue>,
215}
216
217impl FromStr for CodegenConfig {
218 type Err = Error;
219
220 fn from_str(content: &str) -> std::result::Result<CodegenConfig, Self::Err> {
221 let config = toml::from_str(content).map_err(|e| Error::Other(format!("codegen: {e}")))?;
222 Ok(config)
223 }
224}