summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Silverstone <dsilvers@digital-scurf.org>2021-05-22 16:29:56 +0100
committerDaniel Silverstone <dsilvers@digital-scurf.org>2021-05-28 20:47:16 +0100
commita128ec218912a995331140e72933c957da508c79 (patch)
tree48e9c8ba4a78b927fe5ca208066489d547ea9f20
parentb87a23e3c3edcb518c9238ee86d6e7682bc742c1 (diff)
downloadsubplot-a128ec218912a995331140e72933c957da508c79.tar.gz
subplotlib: Document more of the prelude
Signed-off-by: Daniel Silverstone <dsilvers@digital-scurf.org>
-rw-r--r--subplotlib/src/prelude.rs126
1 files changed, 122 insertions, 4 deletions
diff --git a/subplotlib/src/prelude.rs b/subplotlib/src/prelude.rs
index b037c05..4f5b781 100644
--- a/subplotlib/src/prelude.rs
+++ b/subplotlib/src/prelude.rs
@@ -1,9 +1,59 @@
-//! The subplotlib prelude
+//! The subplotlib prelude.
+//!
+//! This prelude is automatically imported into all generated subplot test suites
+//! using the `rust` template. Effectively they get
+//!
+//! ```rust
+//! use subplotlib::prelude::*;
+//! ```
+//!
+//! inserted into them at the top of the file.
+//!
+//! You should familiarise yourself with the context-related types if you
+//! are writing your own contexts, or writing step functions which use
+//! the contexts provided by the [step library][crate::steplibrary] itself.
+//!
+//! The primary thing you will need to learn, as a step function author, is
+//! the [`#[step]`][macro@step] attribute macro, and it interacts with contexts.
// Re-export fehler's macros so that step functions can use them
-#[doc(inline)]
pub use fehler::throw;
-#[doc(inline)]
+/// Indicate what type a function throws
+///
+/// This attribute macro comes from the [`fehler`] crate and is used
+/// to indicate that a function "throws" a particular kind of error.
+///
+/// ```rust
+/// # use std::io;
+/// # use fehler::throws;
+/// #[throws(io::Error)]
+/// fn create_thingy() {
+/// // something which might cause an io::Error
+/// }
+/// # fn main() {}
+/// ```
+///
+/// It transforms a function such that the above function would be compiled
+/// effectively as:
+///
+/// ```rust
+/// # use std::io;
+/// fn create_thingy() -> Result<(), io::Error> {
+/// // something which might cause an io::Error
+/// Ok(())
+/// }
+/// ```
+///
+/// Return statements and the final expression of the function automatically
+/// get wrappered with [`Ok`][std::result::Result::Ok]. You can use the
+/// [`throw`][macro@throw] macro inside such a function to automatically return
+/// an error.
+///
+// When https://github.com/rust-lang/rust/issues/83976 is resolved, the below
+// can be added to this doc string.
+// You can see more documentation on this in the [fehler crate docs][fehler::throws].
+// Alternatively we can get rid of this entirely if and when
+// https://github.com/rust-lang/rust/issues/81893 is fixed.
pub use fehler::throws;
// Re-export the lazy_static macro
@@ -11,7 +61,75 @@ pub use fehler::throws;
pub use lazy_static::lazy_static;
// Re-export subplotlib-derive's macros so that #[step] works
-#[doc(inline)]
+// We have to document it here because we're referring to things
+// inside subplotlib.
+/// Mark a function as a Subplot step function.
+///
+/// This attribute macro is used to indicate that a given function is
+/// a step which can be bound to Subplot scenario statements.
+///
+/// In its simplest form, you use this thusly:
+///
+/// ```rust
+/// # use subplotlib::prelude::*;
+/// # #[derive(Default)] struct SomeContextType;
+/// # impl ContextElement for SomeContextType {}
+/// #[step]
+/// fn my_step_function(context: &mut SomeContextType, arg1: &str, arg2: &str)
+/// {
+/// // Do something appropriate here.
+/// }
+/// # fn main() {}
+/// ```
+///
+/// Step functions must be pretty basic. For now at least they cannot be async,
+/// and they cannot be generic, take variadic arguments, be unsafe, etc.
+///
+/// The first argument to the step function is considered the step's context.
+/// Anything which implements
+/// [`ContextElement`] can be used here. You
+/// can take either a `&ContextType` or `&mut ContextType` as your context. It's
+/// likely best to take the shared borrow if you're not altering the context at all.
+///
+/// If you require access to a number of context objects as part of your step
+/// function implementation, then there is the high level container
+/// [`ScenarioContext`]. You should take
+/// this high level container as a shared borrow, and then within your step function
+/// you can access other contexts as follows:
+///
+/// ```rust
+/// # use subplotlib::prelude::*;
+/// # #[derive(Default)] struct ContextA;
+/// # #[derive(Default)] struct ContextB;
+/// # impl ContextElement for ContextA {}
+/// # impl ContextElement for ContextB {}
+/// # impl ContextA { fn get_thingy(&self) -> Result<usize, StepError> { Ok(0) } }
+/// # impl ContextB { fn do_mut_thing(&mut self, _n: usize, _arg: &str) -> Result<(), StepError> { Ok(()) } }
+/// #[step]
+/// #[context(ContextA)]
+/// #[context(ContextB)]
+/// fn my_step(context: &ScenarioContext, arg: &str) {
+/// let thingy = context.with(|ctx: &ContextA| ctx.get_thingy(), false )?;
+/// context.with_mut(|ctx: &mut ContextB| ctx.do_mut_thing(thingy, arg), false)?;
+/// }
+/// # fn main() {}
+/// ```
+///
+/// Importantly here there is the `#[context(SomeContext)]` attribute to tell
+/// the system that you use that context in your step function (without this,
+/// the relevant context may not be initialised for the scenario). The mechanism
+/// to then access contexts from the step function is the
+/// [`ScenarioContext::with`] and
+/// [`ScenarioContext::with_mut`]
+/// functions which allow shared, or mutable, access to scenario contexts respectively.
+///
+/// These functions take two arguments, the first is a closure which will be run
+/// with access to the given context and whose return value will be ultimately
+/// returned by the call to the function. The second is whether or not to defuse
+/// the poison on the context mutex. In normal steps this should be `false` since
+/// you want a step to fail if the context has been poisoned. However, in cleanup
+/// related step functions you probably want to defuse the poison and be careful in
+/// how you then use the contexts so that you can clean up effectively.
pub use subplotlib_derive::step;
// Re-export the step result types