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
use crate::construction::enablers::ScheduleKeys;
use crate::construction::features::CapacityKeys;
use crate::construction::heuristics::StateKeyRegistry;
use crate::models::common::{Dimensions, ValueDimension};
use crate::solver::HeuristicKeys;
use rosomaxa::prelude::GenericError;
use std::sync::Arc;

/// Specifies a type used to store any values regarding problem configuration.
pub struct Extras {
    index: Dimensions,
}

impl Extras {
    /// Returns a shared reference for the value under the given key.
    pub fn get_value_raw<T: 'static + Send + Sync>(&self, key: &str) -> Option<Arc<T>> {
        self.index.get(key).cloned().and_then(|any| any.downcast::<T>().ok())
    }
}

/// Provide the safe way to construct instance of `Extras`.
pub struct ExtrasBuilder(Extras);

impl Default for ExtrasBuilder {
    fn default() -> Self {
        Self::new(&mut StateKeyRegistry::default())
    }
}

impl From<&Extras> for ExtrasBuilder {
    fn from(extras: &Extras) -> Self {
        Self(Extras { index: extras.index.clone() })
    }
}

impl ExtrasBuilder {
    /// Creates an instance of `ExtrasBuilder` using `registry` to initialize required keys.
    pub fn new(state_registry: &mut StateKeyRegistry) -> Self {
        let mut builder = Self(Extras { index: Default::default() });

        builder
            .with_schedule_keys(ScheduleKeys::from(&mut *state_registry))
            .with_capacity_keys(CapacityKeys::from(&mut *state_registry))
            .with_heuristic_keys(HeuristicKeys::from(&mut *state_registry));

        builder
    }

    /// Adds schedule keys.
    pub fn with_schedule_keys(&mut self, schedule_keys: ScheduleKeys) -> &mut Self {
        self.0.set_value("schedule_keys", schedule_keys);
        self
    }

    /// Adds capacity keys.
    pub fn with_capacity_keys(&mut self, capacity_keys: CapacityKeys) -> &mut Self {
        self.0.set_value("capacity_keys", capacity_keys);
        self
    }

    /// Adds heuristic keys.
    pub fn with_heuristic_keys(&mut self, heuristic_keys: HeuristicKeys) -> &mut Self {
        self.0.set_value("heuristic_keys", heuristic_keys);
        self
    }

    /// Adds a custom key-value pair to extras.
    pub fn with_custom_key<T: 'static + Sync + Send>(&mut self, key: &str, value: Arc<T>) -> &mut Self {
        self.0.index.insert(key.to_string(), value);
        self
    }

    /// Builds extras.
    pub fn build(&mut self) -> Result<Extras, GenericError> {
        // NOTE: require setting keys below as they are used to calculate important internal
        // metrics such as total cost, rosomaxa weights, etc.

        let error =
            [("schedule_keys", "schedule keys needs to be set"), ("heuristic_keys", "heuristic keys needs to be set")]
                .iter()
                .filter(|(key, _)| !self.0.index.contains_key(*key))
                .map(|(_, msg)| GenericError::from(*msg))
                .next();

        if let Some(error) = error {
            return Err(error);
        }

        Ok(Extras { index: std::mem::take(&mut self.0.index) })
    }
}

/// Keeps track of state keys used in core which can be useful in other contexts too.
///
/// For example, transport keys provide information about total duration/distance traveled by vehicle
/// which can be used in heuristic context to compare different routes.
pub trait CoreStateKeys {
    /// Get state keys for scheduling.
    fn get_schedule_keys(&self) -> Option<&ScheduleKeys>;

    /// Gets state keys for capacity feature.
    fn get_capacity_keys(&self) -> Option<&CapacityKeys>;

    /// Gets state keys for heuristic.
    fn get_heuristic_keys(&self) -> Option<&HeuristicKeys>;
}

impl CoreStateKeys for Extras {
    fn get_schedule_keys(&self) -> Option<&ScheduleKeys> {
        self.get_value("schedule_keys")
    }

    fn get_capacity_keys(&self) -> Option<&CapacityKeys> {
        self.get_value("capacity_keys")
    }

    fn get_heuristic_keys(&self) -> Option<&HeuristicKeys> {
        self.get_value("heuristic_keys")
    }
}

impl ValueDimension for Extras {
    fn get_value<T: 'static>(&self, key: &str) -> Option<&T> {
        self.index.get_value(key)
    }

    fn set_value<T: 'static + Sync + Send>(&mut self, key: &str, value: T) {
        self.index.set_value(key, value)
    }
}