diff --git a/images/demo_output.png b/images/demo_output.png new file mode 100644 index 0000000..79be895 Binary files /dev/null and b/images/demo_output.png differ diff --git a/images/demo_output_renamed.png b/images/demo_output_renamed.png new file mode 100644 index 0000000..6aab9b7 Binary files /dev/null and b/images/demo_output_renamed.png differ diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 88d3a8f..1762df4 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -24,3 +24,9 @@ - [Stringifiers](attrs/stringifiers.md) - [Notes on Diplomat and safety](safety.md) - [Backend developer guide](developer.md) +- [demo_gen](demo_gen/intro.md) + - [Quickstart](demo_gen/quickstart.md) + - [Attributes](demo_gen/attributes.md) + - [Configuring Markup](demo_gen/markup.md) + - [Configuring the Default Renderer](demo_gen/renderer.md) + - [Making Your Own Renderer](demo_gen/custom_renderer.md) \ No newline at end of file diff --git a/src/demo_gen/attributes.md b/src/demo_gen/attributes.md new file mode 100644 index 0000000..a97ac42 --- /dev/null +++ b/src/demo_gen/attributes.md @@ -0,0 +1,86 @@ +# Attributes + +demo_gen does a lot in its attempt to automagically generate demonstrations for you. Sometimes however, hands on configuration is required. + +Find below a list of the attributes that demo_gen supports. + +## \#\[diplomat::attr\] + +demo_gen supports all attributes listed in the [attrs chapter](../attrs.md). You mostly will want to use the `disable` attribute, to disable any functions that you may not want to include in output. + +Because demo_gen is so heavily based on the JS backend, any `#[diplomat::attr]`s that apply to the JS backend will also apply to the demo_gen backend. So for example, any methods disabled in the JS backend will also be disabled in demo_gen's output. + +## \#\[diplomat::demo\] + +This is the core attribute that demo_gen looks for in configuring its output. There are a few supported attributes currently: + +### \#\[diplomat::demo(generate)\] + +Used in explicit generation of output. See [markup](./markup.md) for more. + +### \#\[diplomat::demo(default_constructor)\] + +demo_gen will throw errors for any Opaque types that do not have a method labelled with this attribute. demo_gen also looks for any Opaque methods labelled with `#[diplomat::attr(auto, constructor)]` as an alternative. + +You should label each Opaque in your FFI definition with a `default_constructor` attribute, where the method is one you expect most users to call regularly when trying to create the Opaque in question. If your Opaque does not have an associated constructor method in its `impl` block, you should consider disabling functions (as this sort of behavior is too advanced for demo_gen to parse correctly). + +For reasons on why demo_gen requires explicit labelling of Opaque constructors, see [the demo_gen design doc](https://github.com/rust-diplomat/diplomat/blob/main/docs/demo_gen.md). + +### \#\[diplomat::demo(external)\] + +Can be used above a parameter, struct field, or Opaque type. + +It represents any input that you want to specify custom behavior for in the [rendering](./renderer.md) Javascript. + +For example: In ICU4X, we have a `DataProvider` Opaque type that must be compiled ahead of time, and so we flag it as an external type: + +```rs +#[diplomat::bridge] +mod ffi { + #[diplomat::opaque] + #[diplomat::demo(external)] + pub struct DataProvider; +} +``` + +We then override the [default renderer's runtime.mjs](renderer.md#runtimemjs) file to provide the compiled `DataProvider` when it is requested. + +### \#\[diplomat::demo(input(...))\] + +For configuring user input to your demos. `input(...)` takes in a comma separated list of values. + +May be used on parameters or struct fields to configure specific properties passed to the [renderer](renderer.md). + +Here are some valid `input` values: + +- `input(label = "Label Here")`. Changes the label a given function parameter will have in the output. + +#### Input Example + +If we modify our [quickstart](quickstart.md) example, we can add `#[diplomat::demo(input(...))]` labels to the function parameters: + +```rs +#[diplomat::bridge] +mod ffi { + use std::fmt::Write; + + #[diplomat::opaque] + #[diplomat::rust_link(basic_adder, Mod)] + pub struct AddResult; + + impl AddResult { + pub fn get_add_str( + #[diplomat::demo(input(label = "x"))] + left : u32, + #[diplomat::demo(input(label = "y"))] + right : u32, write: &mut DiplomatWrite) { + write.write_str(&format!("{}", basic_adder::add(left, right))).unwrap(); + write.flush(); + } + } +} +``` + +Which creates the following HTML output: + +!["AddResult.getAddStr" in large text. Below are two inputs: one labelled "x" that has a value of 10, and one labelled "y" that has a value of 2. Below is a submit button. There is output below the button, with the label "Output" and a value of 12.](../../images/demo_output_renamed.png) \ No newline at end of file diff --git a/src/demo_gen/custom_renderer.md b/src/demo_gen/custom_renderer.md new file mode 100644 index 0000000..f5e6a13 --- /dev/null +++ b/src/demo_gen/custom_renderer.md @@ -0,0 +1,9 @@ +# Making Your Own Renderer + +Inside of `index.mjs`, demo_gen outputs an object called `RenderInfo` that points to all the functions demo_gen has created for the purposes of demonstration. + +`RenderInfo` gives you the function to call directly, as well as the required parameters needed for each function in order. + +This is meant to slot in to almost any Javascript solution with ease, but if there's an issue with `RenderInfo`s setup that is not quite compatible with your solution, please [open an issue](https://github.com/rust-diplomat/diplomat/issues/new?labels=B-demo_gen). + +The exact structure of `RenderInfo` is available in the demo_gen [design docs](https://github.com/rust-diplomat/diplomat/blob/main/docs/design_doc.md#step-two-constructing-renderinfo). \ No newline at end of file diff --git a/src/demo_gen/intro.md b/src/demo_gen/intro.md new file mode 100644 index 0000000..2a85cf0 --- /dev/null +++ b/src/demo_gen/intro.md @@ -0,0 +1,18 @@ +# demo_gen + +## What is demo_gen? + +demo_gen is a backend for creating demonstration webpages automatically from Diplomat FFI definitions. These webpages are meant to showcase the capabilities of your library. + + +You can view the tracking issue for the demo_gen backend [here](https://github.com/rust-diplomat/diplomat/issues/604). + +If you're interested in the design behind demo_gen, we have a [design document](https://github.com/rust-diplomat/diplomat/blob/main/docs/demo_gen.md) viewable on the Diplomat repository. + +## Why do I want to use demo_gen? + +The current big-name use case for demo_gen is the ICU4X internationalization library. ICU4X has a wide breadth of functions that can be somewhat hard to grasp if you're not already using the library heavily. demo_gen is a quick way + +You can view the ICU4X demo_gen results [here](https://ambiguous.name/icu4x/) for a full demonstration of what demo_gen is currently capable. + +If you're interested in trying demo_gen yourself, hop on to the [Quickstart](./quickstart.md) page to get started! \ No newline at end of file diff --git a/src/demo_gen/markup.md b/src/demo_gen/markup.md new file mode 100644 index 0000000..eda2b36 --- /dev/null +++ b/src/demo_gen/markup.md @@ -0,0 +1,25 @@ +# Configuring Markup +Diplomat takes the `-l` or `--library-config` option (in `diplomat_tool::gen` this is the `library_config` parameter). This represents a path to a `.toml` file that demo_gen will then read and convert into `DemoConfig`. + +Here's a sample .toml file for configuration (with comments for clarity): + +```toml +# If false, demo_gen will automatically search all methods for functions it can generate demonstration JS for. +# If true, demo_gen will look for any methods explicitly flagged with #[diplomat::demo(generate)] to perform generation. +explicit-generation=true # default = false (bool) + +# This removes the rendering/ folder. +hide-default-renderer=true # default = false (bool) + +# Adjusts all imports that demo_gen creates to a specific module. Setting this will not generate the js/ folder. +# +# So for instance, this setting will adjust imports to: `import { type } from "icu4x"; +module-name="icu4x" # (string) + +# Adjusts all imports that demo_gen creates to a relative path where Diplomat JS output should be. Setting this will not generate the js/ folder. +# +# Setting this will adjust imports to: `import {type} from "../js/folder/here/index.mjs"; +# +# Intended to be a mutually exclusive setting with module-name, although you can set both simultaneously to import modules from a relative path. +relative-js-path="../js/folder/here" # (string) +``` \ No newline at end of file diff --git a/src/demo_gen/quickstart.md b/src/demo_gen/quickstart.md new file mode 100644 index 0000000..22e9b43 --- /dev/null +++ b/src/demo_gen/quickstart.md @@ -0,0 +1,103 @@ +# Quickstart + +Demo Gen takes a bit of configuration if you don't already have your own Diplomat library set up. + +For that reason, we have a [quickstart repository](https://github.com/rust-diplomat/demo-gen-quickstart). You can also follow along in your own library if you'd like. + +## Requirements + +You'll need to clone [the repository](https://github.com/rust-diplomat/demo-gen-quickstart). + +You'll need to have Rust, Cargo, and the `wasm32-unknown-unknown` target installed: + +```sh +rustup target add wasm32-unknown-unknown +``` + +You'll also need `Node` and `npm` [installed](https://nodejs.org/en/download/package-manager), as Diplomat generates JS code in modules that is easier for Node to parse as a package. + +## Getting Started + +You just need to run (in the repository folder): + +```sh +cargo build -p adder_bindings --target wasm32-unknown-unknown +cargo run -p generator +cp target/wasm32-unknown-unknown/debug/adder_bindings.wasm adder_bindings/demo +``` + +You'll notice the `demo` folder now has a `demo_gen` folder, which is full of JS and rendering files. We can view our results in an HTTP server: + +```sh +npm -C adder_bindings/demo install +npm -C adder_bindings/demo run start +``` + +If you open the server, you should see a webpage listing `AddResult.getAddStr` with a link. If you click the link, you should see something like: + +![A search bar for the web server, with the added URL /demo_gen/rendering/template.html?func=AddResult.getAddStr. Displayed on the webpage is "AddResult.getAddStr" in large text. Below are two inputs: one labelled "left" that has a value of 1, and one labelled "right" that has a value of 2. Below is a submit button. There is output below the button, with the label "Output" and a value of 3.](../../images/demo_output.png) + +And that's it! Let's talk about what each step means. + +# What We Just Accomplished + +When you clone the repository, you'll notice three packages. + +## The Library + +`basic_adder` is our Rust library that we want to make examples of. It only has one function: + +```rs +pub fn add(left: u64, right: u64) -> u64 { + left + right +} +``` + +Everything else we build will be based on this. + +## The Bindings + +`adder_bindings` is our [Diplomat bridge](../basics.md). When we want to make our library accessible in other languages, we need to run `diplomat-tool` on these bindings. + +We build these bundings with + +```sh +cargo build -p adder_bindings --target wasm32-unknown-unknown +``` + +`--target wasm32-unknown-unknown` tells `cargo` to build a `.wasm` file. + +For more on how you can explicitly configure your bindings to work better in demos, see [the chapter on attributes](attributes.md). + +## The Generator + +`generator` is our wrapper for calling `diplomat-tool`. demo_gen is still in progress, and so we need a wayt to use the latest version of `diplomat-tool` to use this experimental backend. `generator` may be removed in future versions of this tutorial. + +We run the generator with + +```sh +cargo run -p generator +``` + +And it performs the equivalent of: + +```sh +diplomat-tool demo_gen adder_bindings/demo/demo_gen --entry adder_bindings/src/lib.rs +``` + +demo_gen will automatically generate JS bindings by default, along with a bunch of other files to help you get started as easily as possible. If you have JS bindings elsewhere, or a different file structure from the Quickstart repository, you can configure how demo_gen works with a library config file. See [the section on markup generation for more](markup.md). + +## The Web Demo + +demo_gen is designed to work with most Diplomat libraries with minimal configuration. However, we currently don't provide *everything* that you'll need to instantly see a demo + +The minimum requirement is at least a web server to load JS modules. + +This is why we have you run + +```sh +npm -C adder_bindings/demo install +npm -C adder_bindings/demo run start +``` + +See the chapter on [the renderer](./renderer.md) for more. \ No newline at end of file diff --git a/src/demo_gen/renderer.md b/src/demo_gen/renderer.md new file mode 100644 index 0000000..a01ddd2 --- /dev/null +++ b/src/demo_gen/renderer.md @@ -0,0 +1,94 @@ +# Configuring the Default Renderer + +demo_gen comes bundled with an HTML renderer to make getting started with creating demo_gen output to be as fast as possible. The default renderer is also designed to be highly customizable for your own preferences or front ends. + +The front end renderer uses [Web Components](https://developer.mozilla.org/en-US/docs/Web/API/Web_components), which are natively supported by most browsers. For this reason, it should be very portable into other front end systems like Svelte or React. However, if you're dead set on a solution that works even *better* for your front end of choice, you should read [making your own renderer](./custom_renderer.md). + +For more on how the default renderer works, you can read our [design doc](https://github.com/rust-diplomat/diplomat/blob/main/docs/design_doc.md). + +Regardless, let's discuss some ways you can customize the default renderer to your liking. + +## template.html + +`rendering/template.html` represents a list of templates that demo_gen's default renderer will use + +demo_gen will automatically generate `template.html` in the rendering folder. There is nothing that ties `template.html` to this folder specifically however; you can copy, modify, and link to a changed `template.html` file for custom HTML, JS, and CSS. + +For instance, this is one template we've overridden in the ICU4X repo to take advantage of Bootstrap: + +```html + +``` + +For `