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