Skip to content

Commit

Permalink
Added some docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael-F-Bryan committed Jul 17, 2022
1 parent b081597 commit 5317244
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 18 deletions.
2 changes: 0 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion crates/plugins/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,5 @@ thiserror = "1.0.31"

[target.'cfg(target_family = "wasm")'.dependencies]
wit-bindgen-rust = { git = "https://github.com/bytecodealliance/wit-bindgen" }
tracing = "0.1.35"
tracing-subscriber = "0.3.14"
chrono = "0.4.19"
5 changes: 4 additions & 1 deletion crates/plugins/src/abi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ extern "Rust" {
/// Declare the function that will be called when a plugin is first initialized.
///
/// This is where you'll do things like registering a model with the host and so
/// on.
/// on. The function should accept a [`&mut dyn Host`][crate::Host] and return
/// a `Result<`[`PluginMetadata`]`,`[`Error`]`>`.
///
/// See [the crate docs][crate] for a more in-depth example.
#[macro_export]
macro_rules! register_plugin {
($init:expr) => {
Expand Down
2 changes: 1 addition & 1 deletion crates/plugins/src/abi/wasm.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{ArgumentMetadata, Context, ModelMetadata, PluginMetadata};
use crate::{ArgumentMetadata, ModelMetadata, PluginMetadata};
use chrono::{DateTime, NaiveDateTime, Utc};
use std::{
fmt,
Expand Down
27 changes: 25 additions & 2 deletions crates/plugins/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
//! Abstractions for defining your own Fornjot plugins.
//! Abstractions and utilities for defining your own Fornjot plugins.
//!
//! # Creating Your Own Plugin
//!
//! The typical workflow is to first define a [`Model`] type. This comes with
//! two main methods,
Expand All @@ -10,6 +12,7 @@
//! use fj_plugins::{Model, Context, ContextExt, Error, ModelMetadata, ArgumentMetadata};
//! use fj::{Shape, Circle, Sketch, syntax::*};
//!
//! #[derive(Default)]
//! struct Cylinder;
//!
//! impl Model for Cylinder {
Expand All @@ -32,6 +35,9 @@
//! }
//! ```
//!
//! (Down the track you'll probably be able to generate most of this with a
//! `#[fj::model]` attribute, but for now it needs to be written manually)
//!
//! Once you've done that, you can use the [`register_plugin!()`] macro to
//! set up the plugin (possibly registering a model) and tell the host some
//! basic information about it.
Expand All @@ -41,19 +47,36 @@
//! # use fj_plugins::{Model, Context, Error, ModelMetadata};
//!
//! fj_plugins::register_plugin!(|host: &mut dyn Host| {
//! host.register_model(Cylinder);
//! host.register_model(Cylinder::default());
//!
//! Ok(PluginMetadata::new(
//! env!("CARGO_PKG_NAME"),
//! env!("CARGO_PKG_VERSION"),
//! ))
//! });
//! # #[derive(Default)]
//! # struct Cylinder;
//! # impl Model for Cylinder {
//! # fn metadata(&self) -> ModelMetadata { unimplemented!() }
//! # fn shape(&self, ctx: &dyn Context) -> Result<fj::Shape, Error> { unimplemented!() }
//! # }
//! ```
//!
//! # Metadata
//!
//! A core part of making plugins easy for Fornjot to reason about is the idea
//! of *Metadata*.
//!
//! For example, if the user wants to add an instance of a model to their
//! drawing, they'll probably want to know what its name is and see a short
//! description of it ([`ModelMetadata`]). Similarly, when configuring the
//! model, Fornjot will want to know which arguments are supported so it is able
//! to populate some sort of properties panel ([`ArgumentMetadata`]).
//!
//! Plugins as a whole expose [`PluginMetadata`], allowing Fornjot to manage
//! multiple plugins at a time and reason about versioning. For those familiar
//! with Rust, most of this metadata will be similar to the `[package]` section
//! in `Cargo.toml`.
#![warn(
missing_copy_implementations,
Expand Down
84 changes: 74 additions & 10 deletions crates/plugins/src/metadata.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,43 @@
/// Information about a particular plugin that can be used by the host for
/// things like introspection and search.
#[derive(Debug, Clone, PartialEq, Eq)]
#[allow(missing_docs)]
pub struct PluginMetadata {
/// A short, human-friendly name used to identify this plugin.
pub name: String,
/// A semver-compliant version number for the plugin.
pub version: String,
/// A short, one-line description of what the plugin does.
pub short_description: Option<String>,
/// A more elaborate description of what the plugin does.
pub description: Option<String>,
/// A link to the plugin's homepage.
pub homepage: Option<String>,
/// A link to the plugin's source code.
pub repository: Option<String>,
/// The name of the software license(s) this plugin is released under.
///
/// This is interpreted as a SPDX license expression (e.g. `MIT OR
/// Apache-2.0`). See [the SPDX site][spdx] for more information.
///
/// [spdx]: https://spdx.dev/spdx-specification-21-web-version/#h.jxpfx0ykyb60
pub license: Option<String>,
}

#[allow(missing_docs)]
impl PluginMetadata {
/// Create metadata for a plugin.
///
/// # Panics
///
/// The `name` and `version` fields must not be empty.
pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
let name = name.into();
assert!(!name.is_empty());
let version = version.into();
assert!(!version.is_empty());

PluginMetadata {
name: name.into(),
version: version.into(),
name,
version,
short_description: None,
description: None,
homepage: None,
Expand All @@ -26,6 +46,7 @@ impl PluginMetadata {
}
}

/// Set the [`PluginMetadata::short_description`] field.
pub fn set_short_description(self, short_description: impl Into<String>) -> Self {
let short_description = short_description.into();
if short_description.is_empty() {
Expand All @@ -38,6 +59,7 @@ impl PluginMetadata {
}
}

/// Set the [`PluginMetadata::description`] field.
pub fn set_description(self, description: impl Into<String>) -> Self {
let description = description.into();
if description.is_empty() {
Expand All @@ -50,6 +72,7 @@ impl PluginMetadata {
}
}

/// Set the [`PluginMetadata::homepage`] field.
pub fn set_homepage(self, homepage: impl Into<String>) -> Self {
let homepage = homepage.into();
if homepage.is_empty() {
Expand All @@ -62,6 +85,7 @@ impl PluginMetadata {
}
}

/// Set the [`PluginMetadata::repository`] field.
pub fn set_repository(self, repository: impl Into<String>) -> Self {
let repository = repository.into();
if repository.is_empty() {
Expand All @@ -74,6 +98,7 @@ impl PluginMetadata {
}
}

/// Set the [`PluginMetadata::license`] field.
pub fn set_license(self, license: impl Into<String>) -> Self {
let license = license.into();
if license.is_empty() {
Expand All @@ -87,33 +112,58 @@ impl PluginMetadata {
}
}

/// Metadata about a [`crate::Model`].
#[derive(Debug, Clone, PartialEq)]
pub struct ModelMetadata {
/// A short, human-friendly name used to identify this model.
pub name: String,
/// A description of what this model does.
pub description: Option<String>,
/// Arguments that the model uses when calculating its geometry.
pub arguments: Vec<ArgumentMetadata>,
}

impl ModelMetadata {
/// Create metadata for a model.
///
/// # Panics
///
/// The `name` must not be empty.
pub fn new(name: impl Into<String>) -> Self {
let name = name.into();
assert!(!name.is_empty());

ModelMetadata {
name: name.into(),
name,
description: None,
arguments: Vec::new(),
}
}

pub fn with_description(mut self, description: impl Into<String>) -> Self {
self.description = Some(description.into());
self
/// Set the [`ModelMetadata::description`].
pub fn with_description(self, description: impl Into<String>) -> Self {
let description = description.into();
if description.is_empty() {
return self;
}

ModelMetadata {
description: Some(description),
..self
}
}

/// Add an argument to the [`ModelMetadata::arguments`] list.
///
/// As a convenience, string literals can be automatically converted into
/// [`ArgumentMetadata`] with no description or default value.
pub fn with_argument(mut self, arg: impl Into<ArgumentMetadata>) -> Self {
self.arguments.push(arg.into());
self
}
}

/// Metadata describing a model's argument.
#[derive(Debug, Clone, PartialEq)]
pub struct ArgumentMetadata {
/// The name used to refer to this argument.
Expand All @@ -126,19 +176,33 @@ pub struct ArgumentMetadata {
}

impl ArgumentMetadata {
/// Create a new [`ArgumentMetadata`].
///
/// # Panics
///
/// The `name` must not be empty.
pub fn new(name: impl Into<String>) -> Self {
let name = name.into();
assert!(!name.is_empty());
ArgumentMetadata {
name: name.into(),
name,
description: None,
default_value: None,
}
}

/// Set the [`ArgumentMetadata::description`].
pub fn with_description(mut self, description: impl Into<String>) -> Self {
self.description = Some(description.into());
let description = description.into();
if description.is_empty() {
return self;
}

self.description = Some(description);
self
}

/// Set the [`ArgumentMetadata::default_value`].
pub fn with_default_value(mut self, default_value: impl Into<String>) -> Self {
self.default_value = Some(default_value.into());
self
Expand Down
1 change: 0 additions & 1 deletion models/cuboid/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ edition = "2021"
crate-type = ["cdylib", "rlib"]

[dependencies]
anyhow = "1.0.58"
fj = { git = "https://github.com/hannobraun/Fornjot" }
fj-plugins = { version = "0.1.0", path = "../../crates/plugins" }
thiserror = "1.0.31"
Expand Down

0 comments on commit 5317244

Please sign in to comment.