1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use indexmap::IndexSet;
use std::io::{BufReader, BufWriter, Read, Write};
mod infer;
mod util;
pub use util::Wrapper;
mod generate;
use generate::{Print, Program};
pub fn generate<R, W>(opts: Options, read: &mut R, write: &mut W) -> anyhow::Result<()>
where
R: Read + ?Sized,
W: Write + ?Sized,
{
let mut reader = BufReader::new(read);
let mut buf = String::new();
reader.read_to_string(&mut buf)?;
let program = Program::generate(json::parse(&buf)?, &buf, &opts);
let mut writer = BufWriter::new(write);
program.print(&mut writer, &opts)?;
Ok(())
}
#[derive(Debug)]
pub struct Options {
pub json_name: Option<String>,
pub root_name: String,
pub make_unit_test: bool,
pub make_main: bool,
pub collapse_option_vec: bool,
pub tuple_max: Option<usize>,
pub default_derives: String,
pub field_naming: CasingScheme,
pub struct_naming: CasingScheme,
pub vec_wrapper: Wrapper,
pub map_wrapper: Wrapper,
}
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum CasingScheme {
Snake,
Pascal,
Constant,
Camel,
Identity,
}
impl CasingScheme {
fn convert(self, input: &str) -> String {
use inflections::Inflect as _;
match self {
Self::Snake => input.to_snake_case(),
Self::Pascal => input.to_pascal_case(),
Self::Constant => input.to_constant_case(),
Self::Camel => input.to_camel_case(),
Self::Identity => input.to_string(),
}
}
}
pub fn no_derives() -> String {
custom::<&str, _>(std::iter::empty())
}
pub fn all_std_derives() -> String {
custom(&[
"Clone",
"Debug",
"PartialEq",
"PartialOrd",
"Eq",
"Ord",
"Hash",
])
}
pub fn custom<S, L>(list: L) -> String
where
S: ToString,
L: IntoIterator<Item = S>,
{
const DEFAULT: [&str; 2] = ["Serialize", "Deserialize"];
list.into_iter()
.flat_map(|s| {
s.to_string()
.split(',')
.filter(|c| !c.starts_with(char::is_numeric))
.map(ToString::to_string)
.collect::<IndexSet<_>>()
})
.filter(|s| !DEFAULT.contains(&&**s))
.chain(DEFAULT.iter().map(ToString::to_string))
.collect::<IndexSet<_>>()
.into_iter()
.fold(String::new(), |mut a, c| {
if !a.is_empty() {
a.push_str(", ");
}
a.push_str(&c);
a
})
}