state_resolver/
lib.rs

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
use std::error::Error;

use serde::{Deserialize, Serialize};
use workflow::spec::{Dataset, User};

/***** ERRORS *****/
/// Defines some errors being constructable in the type used in the [`StateResolver`].
pub trait StateResolverError {
    /// Checks if this error was generated because the `use_case` identifier supplied to [`StateResolver::get_state()`] was not recognized.
    ///
    /// # Returns
    /// The given use_case identifier as a [`String`], or [`None`] if this error does not represent this case.
    fn try_as_unknown_use_case(&self) -> Option<&String>;
}

/// We implement it for `std::convert::Infallible` to allow implementations to not care about errors.
impl StateResolverError for std::convert::Infallible {
    #[inline]
    fn try_as_unknown_use_case(&self) -> Option<&String> {
        // It will never error, so it can never be an unknown case
        None
    }
}

/***** AUXILLARY *****/
/// The state that captures runtime context, returned by a [`StateResolver`] dynamically.
///
/// This defines everything a policy gets to know about the state of the system at the time a policy is being checked.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct State {
    // Only scientists for now
    pub users:     Vec<User>,
    pub locations: Vec<User>,
    pub datasets:  Vec<Dataset>,
    pub functions: Vec<Dataset>,
    // TODO: Somehow add events / audit trail
    // TODO: Somehow add duties or duty policies, maybe encode in Dataset?
}

/***** LIBRARY *****/
/// Defines how a state resolver looks like in general.
#[async_trait::async_trait]
pub trait StateResolver {
    /// The error type emitted by this trait's functions.
    ///
    /// Note that the error is supposed to implement [`StateResolverError`] to communicate standard errors.
    type Error: 'static + Send + StateResolverError + Sync + Error;

    /// Retrieves the current reasoner state necessary for resolving policies.
    ///
    /// Note that this state is agnostic to the specific reasoner connector used (and therefore policy language).
    ///
    /// # Arguments
    /// - `use_case`: Some identifier that allows the state resolver to assume a different state depending on the use-case used.
    ///
    /// # Returns
    /// A new [`State`] struct that encodes the current state.
    ///
    /// # Errors
    /// This function may error whenever it likes. However, it's recommended to trigger the errors specified in the [`StateResolverError`] trait if applicable.
    async fn get_state(&self, use_case: String) -> Result<State, Self::Error>;
}