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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
//! This module keeps track of al the Memory related abstraction
//! Memory is considered the layer that keeps track of the exercise, submission, user...
//! It's not important how it is implemented, or how the data are structured. It has to respond to some simple queries in the Memory trait.
//!
//! The Memory trait is actualy formed by two traits: StatelessMemory and StateMemory.
//! This is needed to expose StateMemory only when it is actualy possible to specify the state.
//!
use std::{any::TypeId, error::Error, fmt::Debug, marker::PhantomData};

pub use async_trait::async_trait;
use chrono::{DateTime, Utc};

use crate::prelude::*;

use private::Privatizer;
mod private {
    /// should remain private, it's needed to privatize what we doesn't want to implement outside this module
    pub trait Privatizer {}
}

/// A valid UserVariant
pub trait UserState: Debug + Privatizer + Clone {}
#[derive(Debug, Clone)]
/// Admin variant, used as a type-state-machine
pub struct Admin;
impl Privatizer for Admin {}
impl UserState for Admin {}

#[derive(Debug, Clone)]
/// Authenticated variant, used as a type-state-machine
pub struct Authenticated;
impl Privatizer for Authenticated {}
impl UserState for Authenticated {}

#[derive(Debug, Clone)]
/// Unauthenticated variant, used as a type-state-machine
pub struct Unauthenticated;
impl Privatizer for Unauthenticated {}
impl UserState for Unauthenticated {}

#[derive(Debug, Clone)]
/// An user, the variant S represent the type of user (if it is Authenticated, Admin, or Unauthenticated).
pub struct User<S: UserState> {
    /// Phantom data used to save the variant
    pub ph: PhantomData<S>,
    /// Univoque identification of a user
    pub user_id: i64,
    /// Univoque Username of a user
    pub username: String,
    /// Hashed password
    pub password_hash: String,
    /// When did it log-in last time?
    pub logged_in_time: Option<DateTime<Utc>>,
    /// Which token should use to authenticate
    pub logged_in_token: Option<String>,
    /// is an admin? Aka can connect to Admin-only parts?
    pub is_admin: bool,
}

impl<S: UserState> User<S> {
    /// WARNING: THIS FUNCTION DOESN'T CHECK IF IS POSSIBLE TO CONVERT, incorrect usage will lead to insecurities
    pub fn transmute<S2: UserState>(self) -> User<S2> {
        User {
            ph: PhantomData,
            user_id: self.user_id,
            username: self.username,
            password_hash: self.password_hash,
            logged_in_time: self.logged_in_time,
            logged_in_token: self.logged_in_token,
            is_admin: self.is_admin,
        }
    }
}

#[async_trait]
/// This is the trait that contains all method of the memory that does not require knowing the state
pub trait StatelessMemory: Sync + Send {
    //USERS

    /// register User, it should not authenticate it
    async fn register(
        &self,
        username: &str,
        password: &str,
    ) -> Result<User<Unauthenticated>, Box<dyn Error>>;

    /// try to log in the relative user
    async fn login(
        &self,
        username: &str,
        password: &str,
    ) -> Result<User<Authenticated>, Box<dyn Error>>;

    /// search an user from his username
    async fn get_by_username(
        &self,
        username: &str,
    ) -> Result<User<Unauthenticated>, Box<dyn Error>>;

    /// get the authenticated user from his token
    async fn get_authenticate(&self, token: &str) -> Result<User<Authenticated>, Box<dyn Error>>;

    /// get an authenticated admin from his token
    async fn get_admin(&self, token: &str) -> Result<User<Admin>, Box<dyn Error>>;

    /// prints out all users
    async fn get_all_users(&self) -> Result<Vec<User<Unauthenticated>>, Box<dyn Error>>;

    ///list exercises names
    async fn list_exercise_names(&self) -> Result<Vec<String>, Box<dyn Error>>;

    ///add submission (on success returns submission id)
    async fn add_submission(
        &self,
        exercise_name: String,
        source: String,
        user: User<Authenticated>,
    ) -> Result<i64, Box<dyn Error + Send + Sync>>;

    ///add exercise result
    async fn add_exercise_result(
        &self,
        submission_id: i64,
        user: User<Authenticated>,
        result: ExerciseResult,
    ) -> Result<(), Box<dyn Error + Send + Sync>>;
}
#[async_trait]
/// This is the trait that contains all method of the memory that does require knowing the state.
/// Is not always available
pub trait StateMemory<S: ExecutorGlobalState> {
    /// used to enable a particular executor
    async fn enable_executor(
        &self,
        input: &S,
        output: &S,
        data: String,
    ) -> Result<(), Box<dyn Error + Send + Sync + 'static>>;
    /// from a particular state, which executor will be triggered? in which order?
    async fn get_execution_plan(
        &self,
        input: &S,
    ) -> Result<Vec<(TypeId, TypeId, String)>, Box<dyn Error + Send + Sync + 'static>>;

    /// add an exercise to memory
    async fn add_exercise(
        &self,
        name: String,
        exercise_type: S,
        source: String,
    ) -> Result<(), Box<dyn Error + Send + Sync + 'static>>;

    /// get an exercise from memory
    /// type, source
    async fn get_exercise(
        &self,
        name: String,
    ) -> Result<(TypeId, String), Box<dyn Error + Send + Sync + 'static>>;
}
/// auto trait that rapresent the union of stateless and state Memory
pub trait Memory<S: ExecutorGlobalState>: StateMemory<S> + StatelessMemory {
    /// conversion into a StatelessMemory
    fn as_stateless(&self) -> &dyn StatelessMemory;
}
impl<S: ExecutorGlobalState, Cur: StateMemory<S> + StatelessMemory> Memory<S> for Cur {
    fn as_stateless(&self) -> &dyn StatelessMemory {
        self
    }
}

#[test]
fn test_typesafeness() {
    let _t: Option<Box<dyn StatelessMemory>> = None;
}