subplotlib/prelude.rs
1//! The subplotlib prelude.
2//!
3//! This prelude is automatically imported into all generated subplot test suites
4//! using the `rust` template. Effectively they get
5//!
6//! ```rust
7//! use subplotlib::prelude::*;
8//! ```
9//!
10//! inserted into them at the top of the file.
11//!
12//! You should familiarise yourself with the context-related types if you
13//! are writing your own contexts, or writing step functions which use
14//! the contexts provided by the [step library][crate::steplibrary] itself.
15//!
16//! The primary thing you will need to learn, as a step function author, is
17//! the [`#[step]`][macro@step] attribute macro, and it interacts with contexts.
18
19// Re-export culpa's macros so that step functions can use them
20pub use culpa::throw;
21/// Indicate what type a function throws
22///
23/// This attribute macro comes from the [`culpa`] crate and is used
24/// to indicate that a function "throws" a particular kind of error.
25///
26/// ```rust
27/// # use std::io;
28/// # use culpa::throws;
29/// #[throws(io::Error)]
30/// fn create_thingy() {
31/// // something which might cause an io::Error
32/// }
33/// # fn main() {}
34/// ```
35///
36/// It transforms a function such that the above function would be compiled
37/// effectively as:
38///
39/// ```rust
40/// # use std::io;
41/// fn create_thingy() -> Result<(), io::Error> {
42/// // something which might cause an io::Error
43/// Ok(())
44/// }
45/// ```
46///
47/// Return statements and the final expression of the function automatically
48/// get wrappered with [`Ok`][std::result::Result::Ok]. You can use the
49/// [`throw`][macro@throw] macro inside such a function to automatically return
50/// an error.
51///
52// When https://github.com/rust-lang/rust/issues/83976 is resolved, the below
53// can be added to this doc string.
54// You can see more documentation on this in the [culpa crate docs][culpa::throws].
55// Alternatively we can get rid of this entirely if and when
56// https://github.com/rust-lang/rust/issues/81893 is fixed.
57pub use culpa::throws;
58
59// Re-export the lazy_static macro
60#[doc(hidden)]
61pub use lazy_static::lazy_static;
62
63// Re-export subplotlib-derive's macros so that #[step] works
64// We have to document it here because we're referring to things
65// inside subplotlib.
66/// Mark a function as a Subplot step function.
67///
68/// This attribute macro is used to indicate that a given function is
69/// a step which can be bound to Subplot scenario statements.
70///
71/// In its simplest form, you use this thusly:
72///
73/// ```rust
74/// # use subplotlib::prelude::*;
75/// # #[derive(Debug, Default)] struct SomeContextType;
76/// # impl ContextElement for SomeContextType {}
77/// #[step]
78/// fn my_step_function(context: &mut SomeContextType, arg1: &str, arg2: &str)
79/// {
80/// // Do something appropriate here.
81/// }
82/// # fn main() {}
83/// ```
84///
85/// Step functions must be pretty basic. For now at least they cannot be async,
86/// and they cannot be generic, take variadic arguments, be unsafe, etc.
87///
88/// The first argument to the step function is considered the step's context.
89/// Anything which implements
90/// [`ContextElement`] can be used here. You
91/// can take either a `&ContextType` or `&mut ContextType` as your context. It's
92/// likely best to take the shared borrow if you're not altering the context at all.
93///
94/// If you require access to a number of context objects as part of your step
95/// function implementation, then there is the high level container
96/// [`ScenarioContext`]. You should take
97/// this high level container as a shared borrow, and then within your step function
98/// you can access other contexts as follows:
99///
100/// ```rust
101/// # use subplotlib::prelude::*;
102/// # #[derive(Debug, Default)] struct ContextA;
103/// # #[derive(Debug, Default)] struct ContextB;
104/// # impl ContextElement for ContextA {}
105/// # impl ContextElement for ContextB {}
106/// # impl ContextA { fn get_thingy(&self) -> Result<usize, StepError> { Ok(0) } }
107/// # impl ContextB { fn do_mut_thing(&mut self, _n: usize, _arg: &str) -> Result<(), StepError> { Ok(()) } }
108/// #[step]
109/// #[context(ContextA)]
110/// #[context(ContextB)]
111/// fn my_step(context: &ScenarioContext, arg: &str) {
112/// let thingy = context.with(|ctx: &ContextA| ctx.get_thingy(), false )?;
113/// context.with_mut(|ctx: &mut ContextB| ctx.do_mut_thing(thingy, arg), false)?;
114/// }
115/// # fn main() {}
116/// ```
117///
118/// Importantly here there is the `#[context(SomeContext)]` attribute to tell
119/// the system that you use that context in your step function (without this,
120/// the relevant context may not be initialised for the scenario). The mechanism
121/// to then access contexts from the step function is the
122/// [`ScenarioContext::with`] and
123/// [`ScenarioContext::with_mut`]
124/// functions which allow shared, or mutable, access to scenario contexts respectively.
125///
126/// These functions take two arguments, the first is a closure which will be run
127/// with access to the given context and whose return value will be ultimately
128/// returned by the call to the function. The second is whether or not to defuse
129/// the poison on the context mutex. In normal steps this should be `false` since
130/// you want a step to fail if the context has been poisoned. However, in cleanup
131/// related step functions you probably want to defuse the poison and be careful in
132/// how you then use the contexts so that you can clean up effectively.
133pub use subplotlib_derive::step;
134
135// Re-export the step result types
136#[doc(inline)]
137pub use crate::types::StepError;
138#[doc(inline)]
139pub use crate::types::StepResult;
140
141// And the step itself
142#[doc(inline)]
143pub use crate::step::ScenarioStep;
144
145// Data files
146#[doc(inline)]
147pub use crate::file::SubplotDataFile;
148
149// Finally a scenario itself
150#[doc(inline)]
151pub use crate::scenario::ContextElement;
152#[doc(inline)]
153pub use crate::scenario::Scenario;
154#[doc(inline)]
155pub use crate::scenario::ScenarioContext;
156
157// Utility functions
158#[doc(inline)]
159pub use crate::utils::base64_decode;