preserves/implementations/rust/preserves-schema/doc/example.md

3.4 KiB

Example

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:

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. To compile schema source code to metaschema instances, use preserves-schemac:

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.1 See the preserves-schemac documentation.

Converting the simpleChatProtocol.prb file to Preserves text syntax lets us read the metaschema instance corresponding to the source code:

cat simpleChatProtocol.prb | preserves-tool convert

The result:

<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), 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:

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:

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