#smithy #interface #codegen #model #url #bindings-generator #source

macro smithy-bindgen

macros for binding codegeneration from smithy files

2 unstable releases

0.2.0 Apr 12, 2023
0.1.0 Feb 28, 2023

#15 in #smithy

38 downloads per month
Used in wasmcloud-provider-httpse…

Apache-2.0 and LGPL-3.0-or-later

380KB
8K SLoC

smithy-bindgen

This crate provides macros for generating rust bindings from smithy interfaces. For most uses of smithy interfaces used to generate rust sources, this can eliminate the need for build.rs and codegen.toml files. codegen.toml is still needed to generate bindings for other languages.

Feedback welcome!

This is a first pass at code generation macro, inspired by wit-bindgen. If you have used codegen.toml, please let us know if this works as a replacement. (one known omission: the params setting from codegen.toml is not yet available in this macro) Other variations may be introduced in the future: one for actor-specific interfaces, provider-specific interfaces, etc.

Quick-start

We recommend that the smithy_bindgen! macro is used inside a mod declaration, or by itself in a separate rust source file, to avoid symbol conflicts with your code.

If you're using a wasmcloud first-party interface, you can specify its path name (relative to the wasmcloud/interfaces repo), followed by its namespace:

// [dependencies]
// smithy-bindgen = "0.1"

mod httpserver {
  smithy_bindgen::smithy_bindgen!("httpserver/httpserver.smithy","org.wasmcloud.interfaces.httpserver");
}
use httpserver::{HttpRequest,HttpResponse};

If you have a smithy interface defined locally, you can load it

mod amazing_foo {
  smithy_bindgen::smithy_bindgen!(
     { path: "./amazing_foo.smithy" }, "org.example.interfaces.foo"
  );
}
use amazing_foo::{Bazinga, Wowza};

Additional syntax forms are listed below.

Note This doesn't replace all the functionality of wasmCloud's interface crates. A few of the wasmCloud interface crates have hand-generated helper functions that are not part of the smithy files. For example, wasmcloud-interface-httpserver contains impl Default and a few constructors for HttpResponse. Those are not generated by smithy_bindgen!. We are planning to move those extra helper functions into a future wasmcloud sdk.

Syntax

The first parameter of the smithy_bindgen! macro can take one of three forms. The second parameter is the namespace used for code generation.

  • one wasmcloud first-party interface

    The single-file parameter is a path relative to the wasmcloud interfaces git repo wasmcloud/interfaces

    smithy_bindgen!("httpserver/httpserver.smithy", "org.wasmcloud.interfaces.httpserver");
    

    The above is shorthand for the following:

    smithy_bindgen!({
      url: "https://cdn.jsdelivr.net/gh/wasmcloud/interfaces",
      files: ["httpserver/httpserver.smithy"]
    }, "org.wasmcloud.interfaces.httpserver" );
    
  • one Model Source

    smithy-bindgen!({
      path: "../interfaces/foo.smithy",
    }, "org.example.interfaces.foo" );
    
  • array of Model Sources

    smithy-bindgen!([
      { path: "../interfaces/foo.smithy" },
      { url: "keyvalue/keyvalue.smithy" },
    ], "org.example.interfaces.foo" );
    

Model Source Specification

A model source contains a url, for http(s) downloads, or a path, for local fs access, that serves as a base, plus files, an optional list of file paths that are appended to the base to build complete url download paths and local file paths. When joining the sub-paths from the files array, '/' is inserted or removed as needed, so that there is exactly one between the base and the sub-path. url must begin with either 'http://' or 'https://'. If path is a relative fs path, it is relative to the folder containing Cargo.toml. files may be omitted if the url or path contains the full path to the .smithy file.

All the following are (syntactically) valid model sources:

{ url: "https://example.com/interfaces/foo.smithy" }
{ url: "https://example.com/interfaces", files: [ "foo.smithy", "bar.smithy" ]}
{ path: "../interfaces/foo.smithy" }
{ path: "../interfaces", files: ["foo.smithy", "bar.smithy"]}

These are all equivalent:

{ path: "/usr/share/interfaces/timer.smithy" }
{ path: "/usr/share/interfaces", files: [ "timer.smithy" ] }
{ path: "/usr/share/interfaces/", files: [ "timer.smithy" ] }

If a model source structure contains no url base and no path base, the url for the github wasmcloud interface repo is used:

url: "https://cdn.jsdelivr.net/gh/wasmcloud/interfaces"

Why would the code generator need to load more than one smithy file? So that interfaces can share common symbols for data structures. Most smithy interfaces already import symbols from the namespace org.wasmcloud.model, defined in wasmcloud-model.smithy. The bindgen tool resolves all symbols by assembling an in-memory schema model from all the smithy sources and namespaces, then traversing through the in-memory model, generating code only for the schema elements in the namespace declared in the second parameter of smithy_bindgen!.

jsdelivr.net urls

cdn.jsdelivr.net mirrors open source github repositories. The url syntax can optionally include a github branch, tag, or commit sha.

Common files

Wasmcloud common model files are always automatically included when compiling models (If you've used codegen.toml files, you may remember that they required all base models to be specified explicitly.)

Namespace

Models may include symbols defined in other models via the use command. Only the symbols defined in the namespace (smithy_bindgen!'s second parameter) will be included in the generated code.

Dependencies

~18–36MB
~577K SLoC