1#![allow(missing_docs)]
2use crate::id::{define_id_getter, define_id_type};
3use crate::region::RegionID;
4use crate::time_slice::{TimeSliceID, TimeSliceLevel};
5use indexmap::IndexMap;
6use serde::Deserialize;
7use serde_string_enum::DeserializeLabeledStringEnum;
8use std::collections::HashMap;
9use std::rc::Rc;
10
11define_id_type! {CommodityID}
12
13pub type CommodityMap = IndexMap<CommodityID, Rc<Commodity>>;
15
16pub type CommodityCostMap = HashMap<(RegionID, u32, TimeSliceID), CommodityCost>;
18
19pub type DemandMap = HashMap<(RegionID, u32, TimeSliceID), f64>;
21
22#[derive(PartialEq, Debug, Deserialize)]
25pub struct Commodity {
26 pub id: CommodityID,
28 pub description: String,
30 #[serde(rename = "type")] pub kind: CommodityType,
33 pub time_slice_level: TimeSliceLevel,
35
36 #[serde(skip)]
37 pub costs: CommodityCostMap,
38 #[serde(skip)]
39 pub demand: DemandMap,
40}
41define_id_getter! {Commodity, CommodityID}
42
43#[derive(PartialEq, Clone, Debug, DeserializeLabeledStringEnum)]
45pub enum BalanceType {
46 #[string = "net"]
47 Net,
48 #[string = "cons"]
49 Consumption,
50 #[string = "prod"]
51 Production,
52}
53
54#[derive(PartialEq, Clone, Debug)]
56pub struct CommodityCost {
57 pub balance_type: BalanceType,
59 pub value: f64,
61}
62
63#[derive(PartialEq, Debug, DeserializeLabeledStringEnum)]
65pub enum CommodityType {
66 #[string = "sed"]
67 SupplyEqualsDemand,
68 #[string = "svd"]
69 ServiceDemand,
70 #[string = "inc"]
71 InputCommodity,
72 #[string = "ouc"]
73 OutputCommodity,
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn test_demand_map() {
82 let time_slice = TimeSliceID {
83 season: "all-year".into(),
84 time_of_day: "all-day".into(),
85 };
86 let value = 0.25;
87 let mut map = DemandMap::new();
88 map.insert(("North".into(), 2020, time_slice.clone()), value);
89
90 assert_eq!(
91 map.get(&("North".into(), 2020, time_slice)).unwrap(),
92 &value
93 )
94 }
95
96 #[test]
97 fn test_commodity_cost_map() {
98 let ts = TimeSliceID {
99 season: "winter".into(),
100 time_of_day: "day".into(),
101 };
102 let value = CommodityCost {
103 balance_type: BalanceType::Consumption,
104 value: 0.5,
105 };
106 let mut map = CommodityCostMap::new();
107 assert!(map
108 .insert(("GBR".into(), 2010, ts.clone()), value.clone())
109 .is_none());
110 assert_eq!(map.get(&("GBR".into(), 2010, ts)).unwrap(), &value);
111 }
112}