# 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);
```
