113 lines
3.4 KiB
Markdown
113 lines
3.4 KiB
Markdown
# Example
|
|
|
|
[preserves-schemac]: https://preserves.dev/doc/preserves-schemac.html
|
|
[preserves-schema-rs]: https://preserves.dev/doc/preserves-schema-rs.html
|
|
|
|
Preserves schemas are written in a syntax that (ab)uses [Preserves text
|
|
syntax][preserves::value::text] as a kind of S-expression. Schema source code looks like this:
|
|
|
|
```preserves-schema
|
|
version 1 .
|
|
Present = <Present @username string> .
|
|
Says = <Says @who string @what string> .
|
|
UserStatus = <Status @username string @status Status> .
|
|
Status = =here / <away @since TimeStamp> .
|
|
TimeStamp = string .
|
|
```
|
|
|
|
Conventionally, schema source code is stored in `*.prs` files. In this example, the source code
|
|
above is placed in `simpleChatProtocol.prs`.
|
|
|
|
The Rust code generator for schemas requires not source code, but instances of the [Preserves
|
|
metaschema](https://preserves.dev/preserves-schema.html#appendix-metaschema). To compile schema
|
|
source code to metaschema instances, use [preserves-schemac][]:
|
|
|
|
```shell
|
|
yarn global add @preserves/schema
|
|
preserves-schemac .:simpleChatProtocol.prs > simpleChatProtocol.prb
|
|
```
|
|
|
|
Binary-syntax metaschema instances are conventionally stored in `*.prb` files. If you have a
|
|
whole directory tree of `*.prs` files, you can supply just "`.`" without the "`:`"-prefixed
|
|
fileglob part.[^converting-metaschema-to-text] See the [preserves-schemac documentation][preserves-schemac].
|
|
|
|
[^converting-metaschema-to-text]:
|
|
Converting the `simpleChatProtocol.prb` file to Preserves text syntax lets us read the
|
|
metaschema instance corresponding to the source code:
|
|
```shell
|
|
cat simpleChatProtocol.prb | preserves-tool convert
|
|
```
|
|
The result:
|
|
```preserves
|
|
<bundle {
|
|
[
|
|
simpleChatProtocol
|
|
]: <schema {
|
|
definitions: {
|
|
Present: <rec <lit Present> <tuple [
|
|
<named username <atom String>>
|
|
]>>
|
|
Says: <rec <lit Says> <tuple [
|
|
<named who <atom String>>
|
|
<named what <atom String>>
|
|
]>>
|
|
Status: <or [
|
|
[
|
|
"here"
|
|
<lit here>
|
|
]
|
|
[
|
|
"away"
|
|
<rec <lit away> <tuple [
|
|
<named since <ref [] TimeStamp>>
|
|
]>>
|
|
]
|
|
]>
|
|
TimeStamp: <atom String>
|
|
UserStatus: <rec <lit Status> <tuple [
|
|
<named username <atom String>>
|
|
<named status <ref [] Status>>
|
|
]>>
|
|
}
|
|
embeddedType: #f
|
|
version: 1
|
|
}>
|
|
}>
|
|
```
|
|
|
|
#### Generating Rust code from a schema
|
|
|
|
Generate Rust definitions corresponding to a metaschema instance with [preserves-schema-rs][].
|
|
The best way to use it is to integrate it into your `build.rs` (see [the
|
|
docs][preserves-schema-rs]), but you can also use it as a standalone command-line tool.
|
|
|
|
The following command generates a directory `./rs/chat` containing rust sources for a module
|
|
that expects to be called `chat` in Rust code:
|
|
|
|
```shell
|
|
preserves-schema-rs --output-dir rs/chat --prefix chat simpleChatProtocol.prb
|
|
```
|
|
|
|
Representative excerpts from one of the generated files, `./rs/chat/simple_chat_protocol.rs`:
|
|
|
|
```rust,noplayground
|
|
pub struct Present {
|
|
pub username: std::string::String
|
|
}
|
|
pub struct Says {
|
|
pub who: std::string::String,
|
|
pub what: std::string::String
|
|
}
|
|
pub struct UserStatus {
|
|
pub username: std::string::String,
|
|
pub status: Status
|
|
}
|
|
pub enum Status {
|
|
Here,
|
|
Away {
|
|
since: std::boxed::Box<TimeStamp>
|
|
}
|
|
}
|
|
pub struct TimeStamp(pub std::string::String);
|
|
```
|