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
//! The host [`Kernel`], responsible for dispatching requests to the local host

use std::fmt;

use async_trait::async_trait;
use tc_error::*;
use tc_state::State;
use tc_transact::TxnId;
use tc_value::Value;
use tcgeneric::*;

use crate::txn::Txn;

use system::System;
use userspace::UserSpace;

pub use userspace::{Class, Library, Service, CLASS, LIB, SERVICE};

mod system;
mod userspace;

/// A part of the host [`Kernel`], responsible for dispatching requests to the local host
#[async_trait]
pub trait Dispatch {
    /// Route a GET request.
    async fn get(&self, txn: &Txn, path: &[PathSegment], key: Value) -> TCResult<State>;

    /// Route a PUT request.
    async fn put(&self, txn: &Txn, path: &[PathSegment], key: Value, value: State) -> TCResult<()>;

    /// Route a POST request.
    async fn post(&self, txn: &Txn, path: &[PathSegment], data: State) -> TCResult<State>;

    /// Route a DELETE request.
    async fn delete(&self, txn: &Txn, path: &[PathSegment], key: Value) -> TCResult<()>;

    /// Finalize a transaction
    async fn finalize(&self, txn_id: TxnId);
}

/// The host kernel, responsible for dispatching requests to the local host
pub struct Kernel {
    system: System,
    userspace: Option<UserSpace>,
}

impl Kernel {
    /// Initialize a new [`Kernel`] with no userspace.
    pub fn bootstrap() -> Self {
        Self {
            system: System,
            userspace: None,
        }
    }

    /// Initialize a new [`Kernel`] with the given userspace.
    pub fn with_userspace(class: Class, library: Library, service: Service) -> Self {
        Self {
            system: System,
            userspace: Some(UserSpace::new(class, library, service)),
        }
    }
}

#[async_trait]
impl Dispatch for Kernel {
    async fn get(&self, txn: &Txn, path: &[PathSegment], key: Value) -> TCResult<State> {
        if let Some(userspace) = &self.userspace {
            if userspace.handles(path) {
                return userspace.get(txn, path, key).await;
            }
        }

        self.system.get(txn, path, key).await
    }

    async fn put(&self, txn: &Txn, path: &[PathSegment], key: Value, value: State) -> TCResult<()> {
        if let Some(userspace) = &self.userspace {
            if userspace.handles(path) {
                return userspace.put(txn, path, key, value).await;
            }
        }

        self.system.put(txn, path, key, value).await
    }

    async fn post(&self, txn: &Txn, path: &[PathSegment], data: State) -> TCResult<State> {
        if let Some(userspace) = &self.userspace {
            if userspace.handles(path) {
                return userspace.post(txn, path, data).await;
            }
        }

        self.system.post(txn, path, data).await
    }

    async fn delete(&self, txn: &Txn, path: &[PathSegment], key: Value) -> TCResult<()> {
        if let Some(userspace) = &self.userspace {
            if userspace.handles(path) {
                return userspace.delete(txn, path, key).await;
            }
        }

        self.system.delete(txn, path, key).await
    }

    async fn finalize(&self, txn_id: TxnId) {
        if let Some(userspace) = &self.userspace {
            userspace.finalize(txn_id).await
        }
    }
}

impl fmt::Debug for Kernel {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("host kernel")
    }
}