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
use super::*;

use std::{
    error,
    fmt,
    sync::{
        atomic::{AtomicUsize, Ordering},
        Arc,
        Once,
    },
};

use crate::config::ConfigError;

mod config;
mod lifecycle;
mod scheduler;
mod system;

pub use config::*;
pub use scheduler::*;
pub use system::*;

static GLOBAL_RUNTIME_COUNT: AtomicUsize = AtomicUsize::new(0);

fn default_runtime_label() -> String {
    let runtime_count = GLOBAL_RUNTIME_COUNT.fetch_add(1, Ordering::SeqCst) + 1;
    format!("kompact-runtime-{}", runtime_count)
}

static mut DEFAULT_ROOT_LOGGER: Option<KompactLogger> = None;
static DEFAULT_ROOT_LOGGER_INIT: Once = Once::new();

fn default_logger() -> &'static KompactLogger {
    unsafe {
        DEFAULT_ROOT_LOGGER_INIT.call_once(|| {
            let decorator = slog_term::TermDecorator::new().stdout().build();
            let drain = slog_term::FullFormat::new(decorator).build().fuse();
            let drain = slog_async::Async::new(drain).chan_size(1024).build().fuse();
            DEFAULT_ROOT_LOGGER = Some(slog::Logger::root_typed(
                Arc::new(drain),
                o!(
                "location" => slog::PushFnValue(|r: &slog::Record<'_>, ser: slog::PushFnValueSerializer<'_>| {
                    ser.emit(format_args!("{}:{}", r.file(), r.line()))
                })
                        ),
            ));
        });
        match DEFAULT_ROOT_LOGGER {
            Some(ref l) => l,
            None => panic!("Can't re-initialise global logger after it has been dropped!"),
        }
    }
}

/// Removes the global default logger
///
/// This causes the remaining messages to be flushed to the output.
///
/// This can't be undone (as in, calling `default_logger()` afterwards again will panic),
/// so make sure you use this only right before exiting the programme.
pub fn drop_default_logger() {
    unsafe {
        drop(DEFAULT_ROOT_LOGGER.take());
    }
}

type SchedulerBuilder = dyn Fn(usize) -> Box<dyn Scheduler>;

type ScBuilder = dyn Fn(&KompactSystem, KPromise<()>, KPromise<()>) -> Box<dyn SystemComponents>;

type TimerBuilder = dyn Fn() -> Box<dyn TimerComponent>;

/// A Kompact system error
#[derive(Debug)]
pub enum KompactError {
    /// A mutex in the system has been poisoned
    Poisoned,
    /// An error occurred loading the HOCON config
    ConfigLoadingError(hocon::Error),
    /// An error occurred reading values from the loaded config
    ConfigError(ConfigError),
    /// Something else occurred
    Other(Box<dyn error::Error>),
}

impl KompactError {
    /// Wrap an arbitrary [Error](std::error::Error) into a `KompactError`
    pub fn from_other<E>(e: E) -> Self
    where
        E: error::Error + 'static,
    {
        KompactError::Other(Box::new(e))
    }
}

impl PartialEq for KompactError {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (KompactError::Poisoned, KompactError::Poisoned) => true,
            (KompactError::ConfigLoadingError(she), KompactError::ConfigLoadingError(ohe)) => {
                she == ohe
            }
            (KompactError::ConfigError(se), KompactError::ConfigError(oe)) => se == oe,
            _ => false,
        }
    }
}

impl From<hocon::Error> for KompactError {
    fn from(e: hocon::Error) -> Self {
        KompactError::ConfigLoadingError(e)
    }
}

impl From<ConfigError> for KompactError {
    fn from(e: ConfigError) -> Self {
        KompactError::ConfigError(e)
    }
}

impl fmt::Display for KompactError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            KompactError::Poisoned => write!(f, "A mutex in the KompactSystem has been poisoned"),
            KompactError::ConfigLoadingError(he) => {
                write!(f, "An issue occurred loading configuration: {}", he)
            }
            KompactError::ConfigError(e) => {
                write!(f, "An issue occurred reading configuration: {}", e)
            }
            KompactError::Other(o) => write!(f, "An unknown issue occurred: {}", o),
        }
    }
}

impl error::Error for KompactError {
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        match self {
            KompactError::Poisoned => None,
            KompactError::ConfigLoadingError(ref e) => Some(e),
            KompactError::ConfigError(ref e) => Some(e),
            KompactError::Other(ref o) => Some(o.as_ref()),
        }
    }
}