diff options
author | Daniel Silverstone <dsilvers@digital-scurf.org> | 2021-05-22 16:29:56 +0100 |
---|---|---|
committer | Daniel Silverstone <dsilvers@digital-scurf.org> | 2021-05-28 20:47:16 +0100 |
commit | a128ec218912a995331140e72933c957da508c79 (patch) | |
tree | 48e9c8ba4a78b927fe5ca208066489d547ea9f20 | |
parent | b87a23e3c3edcb518c9238ee86d6e7682bc742c1 (diff) | |
download | subplot-a128ec218912a995331140e72933c957da508c79.tar.gz |
subplotlib: Document more of the prelude
Signed-off-by: Daniel Silverstone <dsilvers@digital-scurf.org>
-rw-r--r-- | subplotlib/src/prelude.rs | 126 |
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 |