1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
//! 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
pub use fehler::throw;
/// 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
#[doc(hidden)]
pub use lazy_static::lazy_static;
// Re-export subplotlib-derive's macros so that #[step] works
// 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(Debug, 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(Debug, Default)] struct ContextA;
/// # #[derive(Debug, 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
#[doc(inline)]
pub use crate::types::StepError;
#[doc(inline)]
pub use crate::types::StepResult;
// And the step itself
#[doc(inline)]
pub use crate::step::ScenarioStep;
// Data files
#[doc(inline)]
pub use crate::file::SubplotDataFile;
// Finally a scenario itself
#[doc(inline)]
pub use crate::scenario::ContextElement;
#[doc(inline)]
pub use crate::scenario::Scenario;
#[doc(inline)]
pub use crate::scenario::ScenarioContext;
// Utility functions
#[doc(inline)]
pub use crate::utils::base64_decode;