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
use std::path::PathBuf;

use either::Either;
use serde::{Deserialize, Serialize};

use super::maps::MapLoadingMode;

pub mod map;
pub mod uniform;

#[derive(Debug, Serialize, Deserialize)]
#[allow(clippy::module_name_repetitions)]
#[serde(deny_unknown_fields)]
#[serde(rename = "SpatiallyExplicit")]
pub struct SpatiallyExplicitArguments {
    #[serde(rename = "habitat", alias = "habitat_map")]
    habitat_map: PathBuf,

    #[serde(rename = "dispersal", alias = "dispersal_map")]
    dispersal_map: PathBuf,

    #[cfg_attr(feature = "spatially-explicit-uniform-turnover", serde(default))]
    turnover: Turnover,

    #[serde(default)]
    #[serde(rename = "mode", alias = "loading_mode")]
    loading_mode: MapLoadingMode,
}

#[cfg(feature = "spatially-explicit-uniform-turnover")]
type UniformTurnoverArguments = uniform::SpatiallyExplicitUniformTurnoverArguments;
#[cfg(not(feature = "spatially-explicit-uniform-turnover"))]
type UniformTurnoverArguments = !;

#[cfg(feature = "spatially-explicit-turnover-map")]
type TurnoverMapArguments = map::SpatiallyExplicitTurnoverMapArguments;
#[cfg(not(feature = "spatially-explicit-turnover-map"))]
type TurnoverMapArguments = !;

impl SpatiallyExplicitArguments {
    #[allow(clippy::missing_errors_doc)]
    pub fn try_load(
        self,
    ) -> Result<Either<UniformTurnoverArguments, TurnoverMapArguments>, String> {
        match self {
            #[cfg(feature = "spatially-explicit-uniform-turnover")]
            Self {
                habitat_map,
                dispersal_map,
                turnover: Turnover::UniformRate(turnover_rate),
                loading_mode,
            } => uniform::SpatiallyExplicitUniformTurnoverArguments::try_load(
                habitat_map,
                dispersal_map,
                turnover_rate,
                loading_mode,
            )
            .map(Either::Left),
            #[cfg(feature = "spatially-explicit-turnover-map")]
            Self {
                habitat_map,
                dispersal_map,
                turnover: Turnover::Map(turnover_map),
                loading_mode,
            } => map::SpatiallyExplicitTurnoverMapArguments::try_load(
                habitat_map,
                dispersal_map,
                turnover_map,
                loading_mode,
            )
            .map(Either::Right),
        }
    }

    #[cfg(feature = "spatially-explicit-uniform-turnover")]
    #[must_use]
    pub fn from_uniform_rate(args: &uniform::SpatiallyExplicitUniformTurnoverArguments) -> Self {
        Self {
            habitat_map: args.habitat_path.clone(),
            dispersal_map: args.dispersal_path.clone(),
            turnover: Turnover::UniformRate(args.turnover_rate),
            loading_mode: args.loading_mode,
        }
    }

    #[cfg(feature = "spatially-explicit-turnover-map")]
    #[must_use]
    pub fn from_map(args: &map::SpatiallyExplicitTurnoverMapArguments) -> Self {
        Self {
            habitat_map: args.habitat_path.clone(),
            dispersal_map: args.dispersal_path.clone(),
            turnover: Turnover::Map(args.turnover_path.clone()),
            loading_mode: args.loading_mode,
        }
    }
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
enum Turnover {
    #[cfg(feature = "spatially-explicit-uniform-turnover")]
    #[serde(rename = "Uniform", alias = "Rate", alias = "UniformRate")]
    UniformRate(necsim_core_bond::PositiveF64),
    #[cfg(feature = "spatially-explicit-turnover-map")]
    Map(PathBuf),
}

#[cfg(feature = "spatially-explicit-uniform-turnover")]
impl Default for Turnover {
    fn default() -> Self {
        Self::UniformRate(necsim_core_bond::PositiveF64::new(0.5_f64).unwrap())
    }
}