#[cfg(test)]
#[path = "../../../tests/unit/format/problem/model_test.rs"]
mod model_test;
extern crate serde_json;
use crate::format::{FormatError, Location};
use serde::{Deserialize, Serialize};
use std::io::{BufReader, BufWriter, Error, Read, Write};
#[derive(Clone, Deserialize, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum RelationType {
Any,
Sequence,
Strict,
}
#[derive(Clone, Deserialize, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Relation {
#[serde(rename(deserialize = "type", serialize = "type"))]
pub type_field: RelationType,
pub jobs: Vec<String>,
pub vehicle_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub shift_index: Option<usize>,
}
#[derive(Clone, Deserialize, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct JobSkills {
#[serde(skip_serializing_if = "Option::is_none")]
pub all_of: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub one_of: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub none_of: Option<Vec<String>>,
}
#[derive(Clone, Deserialize, Debug, Serialize)]
pub struct JobPlace {
pub location: Location,
pub duration: f64,
#[serde(skip_serializing_if = "Option::is_none")]
pub times: Option<Vec<Vec<String>>>,
}
#[derive(Clone, Deserialize, Debug, Serialize)]
pub struct JobTask {
pub places: Vec<JobPlace>,
#[serde(skip_serializing_if = "Option::is_none")]
pub demand: Option<Vec<i32>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tag: Option<String>,
}
#[derive(Clone, Deserialize, Debug, Serialize)]
pub struct Job {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub pickups: Option<Vec<JobTask>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub deliveries: Option<Vec<JobTask>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub replacements: Option<Vec<JobTask>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub services: Option<Vec<JobTask>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub priority: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub skills: Option<JobSkills>,
}
#[derive(Clone, Deserialize, Debug, Serialize)]
pub struct Plan {
pub jobs: Vec<Job>,
#[serde(skip_serializing_if = "Option::is_none")]
pub relations: Option<Vec<Relation>>,
}
#[derive(Clone, Deserialize, Debug, Serialize)]
pub struct VehicleCosts {
#[serde(skip_serializing_if = "Option::is_none")]
pub fixed: Option<f64>,
pub distance: f64,
pub time: f64,
}
#[derive(Clone, Deserialize, Debug, Serialize)]
pub struct ShiftStart {
pub earliest: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub latest: Option<String>,
pub location: Location,
}
#[derive(Clone, Deserialize, Debug, Serialize)]
pub struct ShiftEnd {
#[serde(skip_serializing_if = "Option::is_none")]
pub earliest: Option<String>,
pub latest: String,
pub location: Location,
}
#[derive(Clone, Deserialize, Debug, Serialize)]
pub struct VehicleShift {
pub start: ShiftStart,
#[serde(skip_serializing_if = "Option::is_none")]
pub end: Option<ShiftEnd>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dispatch: Option<Vec<VehicleDispatch>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub breaks: Option<Vec<VehicleBreak>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub reloads: Option<Vec<VehicleReload>>,
}
#[derive(Clone, Deserialize, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct VehicleDispatch {
pub location: Location,
pub limits: Vec<VehicleDispatchLimit>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tag: Option<String>,
}
#[derive(Clone, Deserialize, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct VehicleDispatchLimit {
pub max: usize,
pub start: String,
pub end: String,
}
#[derive(Clone, Deserialize, Debug, Serialize)]
pub struct VehicleReload {
pub location: Location,
pub duration: f64,
#[serde(skip_serializing_if = "Option::is_none")]
pub times: Option<Vec<Vec<String>>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tag: Option<String>,
}
#[derive(Clone, Deserialize, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct VehicleLimits {
#[serde(skip_serializing_if = "Option::is_none")]
pub max_distance: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub shift_time: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tour_size: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub allowed_areas: Option<Vec<AreaLimit>>,
}
#[derive(Clone, Deserialize, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AreaLimit {
pub priority: Option<usize>,
pub outer_shape: Vec<Location>,
}
#[derive(Clone, Deserialize, Debug, Serialize)]
#[serde(untagged)]
pub enum VehicleBreakTime {
TimeWindow(Vec<String>),
TimeOffset(Vec<f64>),
}
#[derive(Clone, Deserialize, Debug, Serialize)]
pub struct VehicleBreak {
pub time: VehicleBreakTime,
pub duration: f64,
#[serde(skip_serializing_if = "Option::is_none")]
pub locations: Option<Vec<Location>>,
}
#[derive(Clone, Deserialize, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct VehicleType {
pub type_id: String,
pub vehicle_ids: Vec<String>,
pub profile: String,
pub costs: VehicleCosts,
pub shifts: Vec<VehicleShift>,
pub capacity: Vec<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub skills: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limits: Option<VehicleLimits>,
}
#[derive(Clone, Deserialize, Debug, Serialize)]
pub struct Profile {
pub name: String,
#[serde(rename(deserialize = "type", serialize = "type"))]
pub profile_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub speed: Option<f64>,
}
#[derive(Clone, Deserialize, Debug, Serialize)]
pub struct Fleet {
pub vehicles: Vec<VehicleType>,
pub profiles: Vec<Profile>,
}
#[derive(Clone, Deserialize, Debug, Serialize)]
pub struct Objectives {
pub primary: Vec<Objective>,
#[serde(skip_serializing_if = "Option::is_none")]
pub secondary: Option<Vec<Objective>>,
}
#[derive(Clone, Deserialize, Debug, Serialize)]
#[serde(tag = "type")]
pub enum Objective {
#[serde(rename(deserialize = "minimize-cost", serialize = "minimize-cost"))]
MinimizeCost,
#[serde(rename(deserialize = "minimize-tours", serialize = "minimize-tours"))]
MinimizeTours,
#[serde(rename(deserialize = "maximize-tours", serialize = "maximize-tours"))]
MaximizeTours,
#[serde(rename(deserialize = "minimize-unassigned", serialize = "minimize-unassigned"))]
MinimizeUnassignedJobs {
#[serde(skip_serializing_if = "Option::is_none")]
breaks: Option<f64>,
},
#[serde(rename(deserialize = "balance-max-load", serialize = "balance-max-load"))]
BalanceMaxLoad {
#[serde(skip_serializing_if = "Option::is_none")]
options: Option<BalanceOptions>,
},
#[serde(rename(deserialize = "balance-activities", serialize = "balance-activities"))]
BalanceActivities {
#[serde(skip_serializing_if = "Option::is_none")]
options: Option<BalanceOptions>,
},
#[serde(rename(deserialize = "balance-distance", serialize = "balance-distance"))]
BalanceDistance {
#[serde(skip_serializing_if = "Option::is_none")]
options: Option<BalanceOptions>,
},
#[serde(rename(deserialize = "balance-duration", serialize = "balance-duration"))]
BalanceDuration {
#[serde(skip_serializing_if = "Option::is_none")]
options: Option<BalanceOptions>,
},
}
#[derive(Clone, Deserialize, Debug, Serialize)]
pub struct BalanceOptions {
#[serde(skip_serializing_if = "Option::is_none")]
pub threshold: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tolerance: Option<f64>,
}
#[derive(Clone, Deserialize, Debug, Serialize)]
pub struct Problem {
pub plan: Plan,
pub fleet: Fleet,
#[serde(skip_serializing_if = "Option::is_none")]
pub objectives: Option<Objectives>,
}
#[derive(Clone, Deserialize, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Matrix {
pub profile: Option<String>,
pub timestamp: Option<String>,
#[serde(alias = "durations")]
pub travel_times: Vec<i64>,
pub distances: Vec<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error_codes: Option<Vec<i64>>,
}
pub fn deserialize_problem<R: Read>(reader: BufReader<R>) -> Result<Problem, Vec<FormatError>> {
serde_json::from_reader(reader).map_err(|err| {
vec![FormatError::new(
"E0000".to_string(),
"cannot deserialize problem".to_string(),
format!("check input json: '{}'", err),
)]
})
}
pub fn deserialize_matrix<R: Read>(reader: BufReader<R>) -> Result<Matrix, Vec<FormatError>> {
serde_json::from_reader(reader).map_err(|err| {
vec![FormatError::new(
"E0001".to_string(),
"cannot deserialize matrix".to_string(),
format!("check input json: '{}'", err),
)]
})
}
pub fn deserialize_locations<R: Read>(reader: BufReader<R>) -> Result<Vec<Location>, Vec<FormatError>> {
serde_json::from_reader(reader).map_err(|err| {
vec![FormatError::new(
"E0000".to_string(),
"cannot deserialize locations".to_string(),
format!("check input json: '{}'", err),
)]
})
}
pub fn serialize_problem<W: Write>(writer: BufWriter<W>, problem: &Problem) -> Result<(), Error> {
serde_json::to_writer_pretty(writer, problem).map_err(Error::from)
}