Skip to content

Commit 7aa8adb

Browse files
authored
Merge pull request #240 from stepchowfun/rust-build-script
Change the Rust code generator to be compatible with Cargo build scripts
2 parents bb26cd6 + 46f5e99 commit 7aa8adb

18 files changed

+109
-112
lines changed

.gitignore

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
# [tag:gitignore] Keep this in sync with [ref:excluded_input_paths].
22
/artifacts/
3-
/example/src/types.rs
4-
/example/target/
5-
/integration_tests/rust/src/types.rs
3+
/examples/rust/target/
64
/integration_tests/rust/target/
75
/integration_tests/typescript/dist
86
/integration_tests/typescript/node_modules/

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.0.3] - 2021-10-14
9+
10+
### Changed
11+
- The Rust code generator is now designed to be invoked by a Cargo build script.
12+
813
## [0.0.2] - 2021-10-09
914

1015
### Changed

CONTRIBUTING.md

+10-39
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ Each of the code generators has a unit test which contains a large string of gen
5454
#!/usr/bin/env ruby
5555

5656
MAX_COLUMNS = 100
57-
GENERATED_CODE_PATH = 'integration_tests/rust/src/types.rs'
57+
GENERATED_CODE_PATH = 'types.rs'
5858

5959
File.read(GENERATED_CODE_PATH).each_line do |line|
6060
line.gsub!('\\', '\\\\\\\\')
@@ -100,59 +100,30 @@ end
100100

101101
## Guidelines for generated code
102102

103-
### Rust
103+
Generally speaking, we aim to have generated code follow the same standards as handwritten code, except when doing so would add significant complexity to the code generator. Below are some additional language-specific considerations.
104104

105-
Generated Rust code should aim to follow the same [guidelines](#rust-style-guide) as handwritten code, with the possible exception of the line length limit.
105+
### Rust
106106

107-
To ensure that generated code will pass Rust and [Clippy](https://github.com/rust-lang/rust-clippy) lint checks now and in the future, it disables the lint checks as follows:
107+
Typical is designed to be invoked by a [Cargo build script](https://doc.rust-lang.org/cargo/reference/build-scripts.html). See the [example project](https://github.com/stepchowfun/typical/tree/main/examples/rust) for how to set that up. The user is expected to create a dedicated source file which locally disables lint checks for that file and then includes the generated code as follows:
108108

109109
```rust
110110
#![allow(clippy::all, clippy::pedantic, clippy::nursery, warnings)]
111-
```
112-
113-
However, our policy is that generated code should pass all checks in `clippy::all`, `clippy::pedantic`, and `warnings`, with the following exemptions:
114-
115-
```rust
116-
#![allow(
117-
clippy::cast_possible_truncation,
118-
clippy::identity_op,
119-
clippy::let_unit_value,
120-
clippy::match_single_binding,
121-
clippy::module_name_repetitions,
122-
clippy::no_effect,
123-
clippy::similar_names,
124-
clippy::too_many_lines,
125-
clippy::unit_arg,
126-
clippy::useless_conversion,
127-
dead_code,
128-
unused_variables,
129-
)]
130-
```
131-
132-
This isn't currently enforced by any CI check. The list of exempt checks can be amended as needed to accommodate future developments, but such amendments must be justified.
133111

134-
To ensure that generated code doesn't cause code formatting checks to fail, the generated code also disables [Rustfmt](https://github.com/rust-lang/rustfmt) for all top-level constructs as follows:
135-
136-
```rust
137-
#[rustfmt::skip]
112+
include!(concat!(env!("OUT_DIR"), "/types.rs"));
138113
```
139114

140-
Our policy is that generated code should be formatted in the same style as handwritten code when doing so doesn't add significant complexity to the code generator, although this is also not enforced by any CI check. The formatting of handwritten code is enforced by Rustfmt in a CI check.
115+
Note that the [Rust integration test](https://github.com/stepchowfun/typical/tree/main/integration_tests/rust) disables specific checks rather than all of them to help us keep track of which checks we are violating.
141116

142117
### TypeScript
143118

144-
Generated Rust code should aim to follow the same standards as handwritten code, with the possible exception of the line length limit.
145-
146-
To ensure that generated code will pass [ESLint](https://eslint.org/) checks now and in the future, it disables ESLint as follows:
119+
To ensure it will pass formatting checks now and in the future, the generated code should disable [Prettier](https://prettier.io/) for all top-level constructs as follows:
147120

148121
```typescript
149-
// eslint-disable
122+
// prettier-ignore
150123
```
151124

152-
To ensure that generated code doesn't cause code formatting checks to fail, the it also disables [Prettier](https://prettier.io/) for all top-level constructs as follows:
125+
To ensure it will pass lint checks now and in the future, the generated code should disable [ESLint](https://eslint.org/) at the file level as follows:
153126

154127
```typescript
155-
// prettier-ignore
128+
// eslint-disable
156129
```
157-
158-
Our policy is that generated code should be formatted in the same style as handwritten code when doing so doesn't add significant complexity to the code generator, although this is also not enforced by any CI check. The formatting of handwritten code is enforced by Prettier in a CI check.

Cargo.lock

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

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "typical"
3-
version = "0.0.2"
3+
version = "0.0.3"
44
authors = ["Stephan Boyer <[email protected]>"]
55
edition = "2018"
66
description = "Algebraic data types for data interchange."

README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ Now that we've defined some types, we can use Typical to generate the code for s
4848
$ typical generate email_api.t --rust-out email_api.rs
4949
```
5050

51+
Refer to the [example Rust project](https://github.com/stepchowfun/typical/tree/main/examples/rust) for how to automate this with a [Cargo build script](https://doc.rust-lang.org/cargo/reference/build-scripts.html).
52+
5153
The client and server can then use the generated code to serialize and deserialize messages for mutual communication. If the client and server are written in different languages, you can generate code for each language.
5254

5355
Note that Typical only does serialization and deserialization. It has nothing to do with service meshes, encryption, authentication, or authorization, but it can be used together with those technologies.
@@ -78,7 +80,7 @@ println!("subject: {}", request.subject);
7880
println!("body: {}", request.body);
7981
```
8082

81-
The full code for this example can be found [here](https://github.com/stepchowfun/typical/tree/main/example).
83+
The full code for this example can be found [here](https://github.com/stepchowfun/typical/tree/main/examples/rust/src/main.rs).
8284

8385
We'll see in the next section why our `SendEmailRequest` type turned into `SendEmailRequestOut` and `SendEmailRequestIn`.
8486

example/README.md

-8
This file was deleted.
File renamed without changes.
File renamed without changes.

examples/rust/README.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Rust example
2+
3+
To run this demonstration, first [install Typical](https://github.com/stepchowfun/typical#installation-instructions) and [Rust](https://www.rust-lang.org/tools/install) if you haven't already. Then run the following command in this directory:
4+
5+
```sh
6+
cargo run
7+
```
8+
9+
Note that you don't need to run Typical directly, since there's a [build script](https://github.com/stepchowfun/typical/blob/main/examples/rust/build.rs) that automates it for you.

examples/rust/build.rs

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
use std::{
2+
env,
3+
io::{stderr, stdout, Write},
4+
path::Path,
5+
process::Command,
6+
};
7+
8+
const SCHEMA_PATH: &str = "types.t";
9+
10+
fn main() {
11+
println!("cargo:rerun-if-changed={}", SCHEMA_PATH);
12+
13+
let out_dir = env::var_os("OUT_DIR").unwrap();
14+
15+
let output = Command::new("typical")
16+
.arg("generate")
17+
.arg(SCHEMA_PATH)
18+
.arg("--rust-out")
19+
.arg(Path::new(&out_dir).join("types.rs"))
20+
.output()
21+
.expect("Failed to run Typical. Is it installed?");
22+
23+
stdout().write_all(&output.stdout).unwrap();
24+
stderr().write_all(&output.stderr).unwrap();
25+
26+
assert!(output.status.success());
27+
}
File renamed without changes.

examples/rust/src/types.rs

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#![allow(clippy::all, clippy::pedantic, clippy::nursery, warnings)]
2+
3+
include!(concat!(env!("OUT_DIR"), "/types.rs"));
File renamed without changes.

integration_tests/rust/build.rs

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
use std::{
2+
env,
3+
io::{stderr, stdout, Write},
4+
path::Path,
5+
process::Command,
6+
};
7+
8+
const SCHEMA_PATH: &str = "../types/main.t";
9+
10+
fn main() {
11+
println!("cargo:rerun-if-changed={}", SCHEMA_PATH);
12+
13+
let out_dir = env::var_os("OUT_DIR").unwrap();
14+
15+
let output = Command::new("typical")
16+
.arg("generate")
17+
.arg(SCHEMA_PATH)
18+
.arg("--rust-out")
19+
.arg(Path::new(&out_dir).join("types.rs"))
20+
.output()
21+
.expect("Failed to run Typical. Is it installed?");
22+
23+
stdout().write_all(&output.stdout).unwrap();
24+
stderr().write_all(&output.stderr).unwrap();
25+
26+
assert!(output.status.success());
27+
}

integration_tests/rust/src/types.rs

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#![allow(
2+
clippy::cast_possible_truncation,
3+
clippy::identity_op,
4+
clippy::let_unit_value,
5+
clippy::match_single_binding,
6+
clippy::module_name_repetitions,
7+
clippy::no_effect,
8+
clippy::similar_names,
9+
clippy::too_many_lines,
10+
clippy::unit_arg,
11+
clippy::useless_conversion,
12+
dead_code,
13+
unused_parens,
14+
unused_variables
15+
)]
16+
17+
include!(concat!(env!("OUT_DIR"), "/types.rs"));

0 commit comments

Comments
 (0)