vrp_pragmatic/format/
mod.rs1extern crate serde_json;
6
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use std::sync::Arc;
10use vrp_core::construction::enablers::ReservedTimesIndex;
11use vrp_core::models::common::{Distance, Duration};
12use vrp_core::models::problem::{Job as CoreJob, Single, VehicleIdDimension};
13use vrp_core::models::solution::Route;
14use vrp_core::models::{Extras as CoreExtras, Problem as CoreProblem, ViolationCode};
15use vrp_core::prelude::{Float, GenericError};
16
17mod coord_index;
18pub use self::coord_index::CoordIndex;
19
20mod dimensions;
21pub use self::dimensions::*;
22
23mod location_fallback;
24pub use self::location_fallback::*;
25
26pub mod problem;
27pub mod solution;
28
29#[derive(Clone, Debug, Deserialize, Serialize)]
31#[serde(untagged)]
32pub enum Location {
33 Coordinate {
35 lat: f64,
37 lng: f64,
39 },
40
41 Reference {
43 index: usize,
45 },
46
47 Custom {
49 r#type: CustomLocationType,
51 },
52}
53
54impl Location {
55 pub fn new_coordinate(lat: f64, lng: f64) -> Self {
57 Self::Coordinate { lat, lng }
58 }
59
60 pub fn new_reference(index: usize) -> Self {
62 Self::Reference { index }
63 }
64
65 pub fn new_unknown() -> Self {
67 Self::Custom { r#type: CustomLocationType::Unknown }
68 }
69
70 pub fn to_lat_lng(&self) -> (f64, f64) {
72 match self {
73 Self::Coordinate { lat, lng } => (*lat, *lng),
74 _ => unreachable!("expect coordinate"),
75 }
76 }
77}
78
79impl std::fmt::Display for Location {
80 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
81 match *self {
82 Location::Coordinate { lat, lng } => write!(f, "lat={lat}, lng={lng}"),
83 Location::Reference { index } => write!(f, "index={index}"),
84 Location::Custom { r#type } => {
85 let value = match r#type {
86 CustomLocationType::Unknown => "unknown",
87 };
88 write!(f, "custom={value}")
89 }
90 }
91 }
92}
93
94#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
96pub enum CustomLocationType {
97 #[serde(rename(deserialize = "unknown", serialize = "unknown"))]
99 Unknown,
100}
101
102#[derive(Clone, Debug, Serialize)]
104pub struct FormatError {
105 pub code: String,
107 pub cause: String,
109 pub action: String,
111 pub details: Option<String>,
113}
114
115impl FormatError {
116 pub fn new(code: String, cause: String, action: String) -> Self {
118 Self { code, cause, action, details: None }
119 }
120
121 pub fn new_with_details(code: String, cause: String, action: String, details: String) -> Self {
123 Self { code, cause, action, details: Some(details) }
124 }
125
126 pub fn to_json(&self) -> String {
128 serde_json::to_string_pretty(&self).unwrap()
129 }
130}
131
132impl std::error::Error for FormatError {}
133
134impl std::fmt::Display for FormatError {
135 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
136 write!(f, "{}, cause: '{}', action: '{}'.", self.code, self.cause, self.action)
137 }
138}
139
140#[derive(Debug)]
142pub struct MultiFormatError {
143 pub errors: Vec<FormatError>,
145}
146
147impl MultiFormatError {
148 pub fn to_json(&self) -> String {
150 serde_json::to_string_pretty(&self.errors).unwrap()
151 }
152}
153
154impl std::error::Error for MultiFormatError {}
155
156impl std::fmt::Display for MultiFormatError {
157 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158 write!(f, "{}", self.errors.iter().map(|err| err.to_string()).collect::<Vec<_>>().join("\n"))
159 }
160}
161
162impl From<Vec<FormatError>> for MultiFormatError {
163 fn from(errors: Vec<FormatError>) -> Self {
164 MultiFormatError { errors }
165 }
166}
167
168impl From<MultiFormatError> for GenericError {
169 fn from(value: MultiFormatError) -> Self {
170 value.to_string().into()
171 }
172}
173
174impl IntoIterator for MultiFormatError {
175 type Item = FormatError;
176 type IntoIter = <Vec<FormatError> as IntoIterator>::IntoIter;
177
178 fn into_iter(self) -> Self::IntoIter {
179 self.errors.into_iter()
180 }
181}
182
183const TIME_CONSTRAINT_CODE: ViolationCode = ViolationCode(1);
184const DISTANCE_LIMIT_CONSTRAINT_CODE: ViolationCode = ViolationCode(2);
185const DURATION_LIMIT_CONSTRAINT_CODE: ViolationCode = ViolationCode(3);
186const CAPACITY_CONSTRAINT_CODE: ViolationCode = ViolationCode(4);
187const BREAK_CONSTRAINT_CODE: ViolationCode = ViolationCode(5);
188const SKILL_CONSTRAINT_CODE: ViolationCode = ViolationCode(6);
189const LOCKING_CONSTRAINT_CODE: ViolationCode = ViolationCode(7);
190const REACHABLE_CONSTRAINT_CODE: ViolationCode = ViolationCode(8);
191const AREA_CONSTRAINT_CODE: ViolationCode = ViolationCode(9);
192const TOUR_SIZE_CONSTRAINT_CODE: ViolationCode = ViolationCode(10);
193const TOUR_ORDER_CONSTRAINT_CODE: ViolationCode = ViolationCode(11);
194const GROUP_CONSTRAINT_CODE: ViolationCode = ViolationCode(12);
195const COMPATIBILITY_CONSTRAINT_CODE: ViolationCode = ViolationCode(13);
196const RELOAD_RESOURCE_CONSTRAINT_CODE: ViolationCode = ViolationCode(14);
197const RECHARGE_CONSTRAINT_CODE: ViolationCode = ViolationCode(15);
198
199pub type JobIndex = HashMap<String, CoreJob>;
201
202pub use self::properties::{CoordIndexExtraProperty, JobIndexExtraProperty};
203
204mod properties {
205 use crate::format::{CoordIndex, JobIndex};
206 use vrp_core::custom_extra_property;
207 use vrp_core::models::Extras;
208
209 custom_extra_property!(JobIndex typeof JobIndex);
210 custom_extra_property!(CoordIndex typeof CoordIndex);
211}
212
213pub fn get_indices(extras: &CoreExtras) -> Result<(Arc<JobIndex>, Arc<CoordIndex>), GenericError> {
215 let job_index = extras.get_job_index().ok_or_else(|| GenericError::from("cannot get job index"))?;
216 let coord_index = extras.get_coord_index().ok_or_else(|| GenericError::from("cannot get coord index"))?;
217
218 Ok((job_index, coord_index))
219}
220
221pub(crate) fn is_correct_vehicle(route: &Route, single: &Single) -> bool {
224 let job_vehicle_id = single.dimens.get_vehicle_id();
225 let job_shift_idx = single.dimens.get_shift_index();
226
227 let vehicle = &route.actor.vehicle;
228 let vehicle_id = vehicle.dimens.get_vehicle_id();
229 let vehicle_shift_idx = vehicle.dimens.get_shift_index();
230
231 job_vehicle_id == vehicle_id && job_shift_idx == vehicle_shift_idx
232}