serde_generate/lib.rs
1// Copyright (c) Facebook, Inc. and its affiliates
2// Copyright (c) Zefchain Labs, Inc.
3// SPDX-License-Identifier: MIT OR Apache-2.0
4
5//! This crate aims to compile the data formats extracted from Rust by [`serde-reflection`](https://crates.io/crates/serde-reflection)
6//! into type definitions and (de)serialization methods for other programming languages.
7//!
8//! It can be used as a library or as a command-line tool (see `serdegen` below).
9//!
10//! ## Supported Languages
11//!
12//! The following programming languages are fully supported as target languages:
13//!
14//! * C++ 17
15//! * Java 8
16//! * Python 3 (requires numpy >= 1.20.1)
17//! * Rust 2018
18//! * Go >= 1.14
19//! * C# (NetCoreApp >= 6.0)
20//! * Swift 5.3
21//! * OCaml
22//! * Dart >= 3
23//! * Kotlin
24//!
25//! The following languages are partially supported and/or still considered under development:
26//!
27//! * TypeScript 4 (packaged and tested with Deno) [(follow-up issue)](https://github.com/zefchain/serde-reflection/issues/58)
28//! * Solidity (tested with Revm) [(initial PR with discussion)](https://github.com/zefchain/serde-reflection/pull/61)
29//!
30//! ## Supported Encodings
31//!
32//! Type definitions in a target language are meant to be used together with a runtime library that
33//! provides (de)serialization in a particular [Serde encoding format](https://serde.rs/#data-formats).
34//!
35//! This crate provides easy-to-deploy runtime libraries for the following binary formats, in all supported languages:
36//!
37//! * [Bincode](https://docs.rs/bincode/1.3.1/bincode/) (default configuration only),
38//! * [BCS](https://github.com/diem/bcs) (short for Binary Canonical Serialization, the main format used
39//! in the [Diem blockchain](https://github.com/diem/diem)).
40//!
41//! ## Quick Start with Python and Bincode
42//!
43//! In the following example, we transfer a `Test` value from Rust to Python using [`bincode`](https://docs.rs/bincode/1.3.1/bincode/).
44//! ```
45//! # #[cfg(feature = "python3")]
46//! # fn main() -> Result<(), std::io::Error> {
47//! use serde::{Deserialize, Serialize};
48//! use serde_reflection::{Registry, Tracer, TracerConfig};
49//! use std::io::Write;
50//!
51//! #[derive(Serialize, Deserialize)]
52//! struct Test {
53//! a: Vec<u64>,
54//! b: (u32, u32),
55//! }
56//!
57//! // Obtain the Serde format of `Test`. (In practice, formats are more likely read from a file.)
58//! let mut tracer = Tracer::new(TracerConfig::default());
59//! tracer.trace_simple_type::<Test>().unwrap();
60//! let registry = tracer.registry().unwrap();
61//!
62//! // Create Python class definitions.
63//! let mut source = Vec::new();
64//! let config = serde_generate::CodeGeneratorConfig::new("testing".to_string())
65//! .with_encodings(vec![serde_generate::Encoding::Bincode]);
66//! let generator = serde_generate::python3::CodeGenerator::new(&config);
67//! generator.output(&mut source, ®istry)?;
68//!
69//! assert!(
70//! String::from_utf8_lossy(&source).contains(
71//! r#"
72//! @dataclass(frozen=True)
73//! class Test:
74//! a: typing.Sequence[st.uint64]
75//! b: typing.Tuple[st.uint32, st.uint32]
76//! "#));
77//!
78//! // Append some test code to demonstrate Bincode deserialization
79//! // using the runtime in `serde_generate/runtime/python/bincode`.
80//! writeln!(
81//! source,
82//! r#"
83//! value = Test.bincode_deserialize(bytes({:?}))
84//! assert value == Test(a=[4, 6], b=(3, 5))
85//! "#,
86//! bincode::serialize(&Test { a: vec![4, 6], b: (3, 5) }).unwrap(),
87//! )?;
88//!
89//! // Execute the Python code.
90//! let mut child = std::process::Command::new("python3")
91//! .arg("-")
92//! .env("PYTHONPATH", std::env::var("PYTHONPATH").unwrap_or_default() + ":runtime/python")
93//! .stdin(std::process::Stdio::piped())
94//! .spawn()?;
95//! child.stdin.as_mut().unwrap().write_all(&source)?;
96//! let output = child.wait_with_output()?;
97//! assert!(output.status.success());
98//! # Ok(())
99//! # }
100//! # #[cfg(not(feature = "python3"))]
101//! # fn main() {}
102//! ```
103//!
104//! ## Binary Tool
105//!
106//! In addition to a Rust library, this crate provides a binary tool `serdegen` to process Serde formats
107//! saved on disk.
108//!
109//! The tool `serdegen` assumes that a Rust value of type `serde_reflection::Registry` has
110//! been serialized into a YAML file. The recommended way to generate such a value is to
111//! use the library `serde-reflection` to introspect Rust definitions (see also the
112//! example above).
113//!
114//! For a quick test, one may create a test file like this:
115//! ```bash
116//! cat >test.yaml <<EOF
117//! ---
118//! Foo:
119//! ENUM:
120//! 0:
121//! A:
122//! NEWTYPE:
123//! U64
124//! 1:
125//! B: UNIT
126//! EOF
127//! ```
128//!
129//! Then, the following command will generate Python class definitions and write them into `test.py`:
130//! ```bash
131//! cargo run -p serde-generate-bin -- --language python3 test.yaml > test.py
132//! ```
133//!
134//! To create a python module `test` and install the bincode runtime in a directory `$DEST`, you may run:
135//! ```bash
136//! cargo run -p serde-generate-bin -- --language python3 --with-runtimes serde bincode --module-name test --target-source-dir "$DEST" test.yaml
137//! ```
138//!
139//! See the help message of the tool with `--help` for more options.
140//!
141//! Note: Outside of this repository, you may install the tool with `cargo install serde-generate-bin` then use `$HOME/.cargo/bin/serdegen`.
142
143/// Dependency analysis and topological sort for Serde formats.
144pub mod analyzer;
145/// Utility function to generate indented text
146pub mod indent;
147
148/// Support for code-generation in C++
149#[cfg(feature = "cpp")]
150pub mod cpp;
151/// Support for code-generation in C#
152#[cfg(feature = "csharp")]
153pub mod csharp;
154/// Support for code-generation in Dart
155#[cfg(feature = "dart")]
156pub mod dart;
157/// Support for code-generation in Go
158#[cfg(feature = "golang")]
159pub mod golang;
160/// Support for code-generation in Java
161#[cfg(feature = "java")]
162pub mod java;
163/// Support for code-generation in Kotlin
164#[cfg(feature = "kotlin")]
165pub mod kotlin;
166/// Support for code-generation in OCaml
167#[cfg(feature = "ocaml")]
168pub mod ocaml;
169/// Support for code-generation in Python 3
170#[cfg(feature = "python3")]
171pub mod python3;
172/// Support for code-generation in Rust
173#[cfg(feature = "rust")]
174pub mod rust;
175/// Support for code-generation in solidity
176#[cfg(feature = "solidity")]
177pub mod solidity;
178/// Support for code-generation in Swift
179#[cfg(feature = "swift")]
180pub mod swift;
181/// Support for code-generation in TypeScript/JavaScript
182#[cfg(feature = "typescript")]
183pub mod typescript;
184
185/// Common logic for codegen.
186mod common;
187/// Common configuration objects and traits used in public APIs.
188mod config;
189
190pub use config::*;