Skip to content

Commit 596dd34

Browse files
committed
initial
0 parents  commit 596dd34

9 files changed

+1096
-0
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/target
2+
**/*.rs.bk
3+
*.json

Cargo.lock

+144
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[package]
2+
name = "json_to_rust"
3+
version = "0.1.0"
4+
authors = ["museun <[email protected]>"]
5+
edition = "2018"
6+
7+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8+
9+
[dependencies]
10+
anyhow = "1.0.31"
11+
indexmap = { version = "1.4.0", features = ["serde-1"] }
12+
serde = { version = "1.0.114", features = ["derive"] }
13+
serde_json = { version = "1.0.56", features = ["preserve_order"] }
14+
inflections = "1.1.1"
15+
heck = "0.3.1"
16+
pico-args = "0.3.3"
17+

LICENSE.txt

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Copyright (C) 2020 by museun <[email protected]>
2+
3+
Permission to use, copy, modify, and/or distribute this software for any purpose
4+
with or without fee is hereby granted.
5+
6+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
7+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
8+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
9+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
10+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
11+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
12+
THIS SOFTWARE.

README.md

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
```
2+
json_to_rust: 0.1.0
3+
4+
description:
5+
pipe some json to this and it'll generate some rust for you.
6+
7+
usage:
8+
< foo.json | json_to_rust -j json_object -n MyStruct > out.rs
9+
10+
flags:
11+
-u, --make-unit-tests generate unit tests
12+
- this generates a unit test that round trips the
13+
- serialization along with the included json sample
14+
15+
-m, --make-main generate a main function
16+
- this generates a main function demoing the
17+
- serialized and deserialized forms
18+
19+
-j, --json-root-name the name of the root JSON object
20+
- this takes a string which'll be the name of
21+
- the root json object, if applicable.
22+
23+
-n, --rust-root-name the name of the root Rust object
24+
- this is the name of your root Rust struct.
25+
- if not provided, its inferred from the json name
26+
27+
-l, --large-struct unroll Objects under this key length
28+
- for large objects, if the length is this or smaller
29+
- a new struct with all possible (seen) fields will be created
30+
31+
32+
-t, --max-tuple heterogeneous arrays under this size will be treated as a tuple
33+
- for types such as [1, false, "foo"] if the length exceeds the provided value
34+
- then a Vec<Value> will be created instead. otherwise a tuple will be created.
35+
- for the example above: a tuple of (i64, bool, String)
36+
37+
-v, --version show the current version
38+
-h, --help show this message
39+
```
40+
41+
License: 0BSD

src/bin/main.rs

+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
use anyhow::Context as _;
2+
use inflections::Inflect as _;
3+
4+
fn header() {
5+
println!("{}: {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
6+
}
7+
8+
fn print_version() -> ! {
9+
header();
10+
std::process::exit(0)
11+
}
12+
13+
fn print_short_help() -> ! {
14+
const HELP_MSG: &str = r#"
15+
description:
16+
pipe some json to this and it'll generate some rust for you.
17+
18+
usage:
19+
< foo.json | json_to_rust -j json_object -n MyStruct > out.rs
20+
21+
flags:
22+
-u, --make-unit-tests generate unit tests
23+
-m, --make-main generate a main function
24+
25+
-j, --json-root-name the name of the root JSON object
26+
-n, --rust-root-name the name of the root Rust object
27+
28+
-l, --large-struct unroll Objects under this key length
29+
-t, --max-tuple heterogeneous arrays under this size will be treated as a tuple
30+
31+
-v, --version show the current version
32+
-h, --help show this message
33+
"#;
34+
35+
header();
36+
println!("{}", HELP_MSG);
37+
std::process::exit(0)
38+
}
39+
40+
fn print_long_help() -> ! {
41+
const HELP_MSG: &str = r#"
42+
description:
43+
pipe some json to this and it'll generate some rust for you.
44+
45+
usage:
46+
< foo.json | json_to_rust -j json_object -n MyStruct > out.rs
47+
48+
flags:
49+
-u, --make-unit-tests generate unit tests
50+
- this generates a unit test that round trips the
51+
- serialization along with the included json sample
52+
53+
-m, --make-main generate a main function
54+
- this generates a main function demoing the
55+
- serialized and deserialized forms
56+
57+
-j, --json-root-name the name of the root JSON object
58+
- this takes a string which'll be the name of
59+
- the root json object, if applicable.
60+
61+
-n, --rust-root-name the name of the root Rust object
62+
- this is the name of your root Rust struct.
63+
- if not provided, its inferred from the json name
64+
65+
-l, --large-struct unroll Objects under this key length
66+
- for large objects, if the length is this or smaller
67+
- a new struct with all possible (seen) fields will be created
68+
69+
70+
-t, --max-tuple heterogeneous arrays under this size will be treated as a tuple
71+
- for types such as [1, false, "foo"] if the length exceeds the provided value
72+
- then a Vec<Value> will be created instead. otherwise a tuple will be created.
73+
- for the example above: a tuple of (i64, bool, String)
74+
75+
-v, --version show the current version
76+
-h, --help show this message
77+
"#;
78+
79+
header();
80+
println!("{}", HELP_MSG);
81+
std::process::exit(0)
82+
}
83+
84+
fn main() -> anyhow::Result<()> {
85+
let mut args = pico_args::Arguments::from_env();
86+
87+
if args.contains(["-v", "--version"]) {
88+
print_version();
89+
}
90+
91+
if args.contains("-h") {
92+
print_short_help();
93+
}
94+
95+
if args.contains("--help") {
96+
print_long_help();
97+
}
98+
99+
let opts = {
100+
let mut opts = json_to_rust::GenerateOptions::default();
101+
if args.contains(["-u", "--make-unit-tests"]) {
102+
opts.make_unit_test = true;
103+
}
104+
if args.contains(["-m", "--make-main"]) {
105+
opts.make_main = true;
106+
}
107+
108+
opts.tuple_max = args.opt_value_from_str(["-t", "--max-tuple"])?;
109+
opts.max_size = args.opt_value_from_str(["-l", "--large-struct"])?;
110+
111+
opts.json_name = args.opt_value_from_str(["-j", "--json-root-name"])?;
112+
113+
opts.root_name = args
114+
.opt_value_from_str(["-n", "--rust-root-name"])?
115+
.or_else(|| opts.json_name.as_ref().map(|s| s.to_pascal_case()))
116+
.with_context(|| {
117+
"`[-n, --rust-root-name]` is required if `[-j, --json-root-name]` is not provided"
118+
})?;
119+
120+
args.finish()?;
121+
122+
opts
123+
};
124+
125+
let stdin = std::io::stdin();
126+
let mut stdin = stdin.lock();
127+
128+
let data = json_to_rust::generate(opts, &mut stdin)?;
129+
println!("{}", data);
130+
131+
Ok(())
132+
}

0 commit comments

Comments
 (0)