use std::fmt;
use std::str::FromStr;
use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::collections::btree_map::*;
use std::io::{BufReader,Read,BufWriter,Write};
use std::fs::File;
use std::io::{Error, ErrorKind};
use crate::primio::*;
#[derive(Default, Debug, Clone, PartialEq)]
pub struct Occupied {
trainnum: String,
trainnum2: String,
from: f64,
until: f64,
}
impl fmt::Display for Occupied {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "<Occupied \"{}\" {:4.2}:{:4.2} \"{}\">",
self.trainnum,self.from,self.until,self.trainnum2)
}
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum OccupiedParseError {
StartSyntaxError,
TrainnumSyntaxError,
FromSyntaxError,
UntilSyntaxError,
Trainnum2SyntaxError,
ExtraCharacters,
}
impl fmt::Display for OccupiedParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
OccupiedParseError::StartSyntaxError =>
write!(f, "Missing '<Occupied '"),
OccupiedParseError::TrainnumSyntaxError =>
write!(f, "Missing trainnum"),
OccupiedParseError::FromSyntaxError =>
write!(f, "Missing from"),
OccupiedParseError::UntilSyntaxError =>
write!(f, "Missing until"),
OccupiedParseError::Trainnum2SyntaxError =>
write!(f, "Missing trainnum2"),
OccupiedParseError::ExtraCharacters =>
write!(f, "Extra trailing characters"),
}
}
}
impl FromStr for Occupied {
type Err = OccupiedParseError;
fn from_str(string: &str) -> Result<Self, Self::Err> {
let (result,pos) = Occupied::ParseOccupied(string)?;
if pos == string.len() {
Ok(result)
} else {
Err(OccupiedParseError::ExtraCharacters)
}
}
}
impl Occupied {
pub fn new(trainnum_: String, from_: f64, until_: f64, trainnum2_: String)
-> Self {
assert!(from_ < until_,"Backwars time tange!");
Self {trainnum: trainnum_, from: from_, until: until_, trainnum2: trainnum2_ }
}
pub fn TrainNum(&self) -> String {self.trainnum.clone()}
pub fn TrainNum2(&self) -> String {self.trainnum2.clone()}
pub fn From(&self) -> f64 {self.from}
pub fn Until(&self) -> f64 {self.until}
pub fn ParseOccupied(string: &str) -> Result<(Self, usize), OccupiedParseError> {
let mut pos: usize;
let trainnum: String;
let trainnum2: String;
let from: f64;
let until: f64;
match string.match_indices("<Occupied \"").next() {
None => return Err(OccupiedParseError::StartSyntaxError),
Some((n, m)) => pos = n + m.len(),
};
match string[pos..].match_indices('"').next() {
None => return Err(OccupiedParseError::TrainnumSyntaxError),
Some((n, m)) => {
trainnum = String::from(&string[pos..n+pos]);
pos += n + m.len();},
}
match string[pos..].match_indices(':').next() {
None => return Err(OccupiedParseError::FromSyntaxError),
Some((n, m)) => {
from = match (string[pos..n+pos].trim()).parse::<f64>() {
Ok(f) => f,
Err(p) => return Err(OccupiedParseError::FromSyntaxError),
};
pos += n + m.len();},
};
match string[pos..].match_indices('"').next() {
None => return Err(OccupiedParseError::UntilSyntaxError),
Some((n, m)) => {
until = match (string[pos..n+pos].trim()).parse::<f64>() {
Ok(u) => u,
Err(p) => return Err(OccupiedParseError::UntilSyntaxError),
};
pos += n + m.len();},
};
match string[pos..].match_indices("\">").next() {
None => return Err(OccupiedParseError::Trainnum2SyntaxError),
Some((n, m)) => {
trainnum2 = String::from(&string[pos..n+pos]);
pos += n + m.len();
},
};
Ok((Self{ trainnum: trainnum, from: from, until: until,
trainnum2: trainnum2}, pos))
}
pub fn Write(&self,f: &mut BufWriter<File>) -> std::io::Result<()> {
write!(f,"<Occupied \"{}\" {:5.3}:{:5.3} \"{}\">",
self.trainnum,self.from,self.until,self.trainnum2)
}
pub fn Read(inp: &mut BufReader<File>) -> std::io::Result<Option<Self>> {
let mut ch: char;
let mut byte: [u8; 1] = [0; 1];
loop {
let status = inp.read(&mut byte)?;
if status == 0 {return Ok(None);}
ch = byte[0] as char;
match ch {
' '|'\t'|'\n' => (),
_ => {break;},
}
}
for c in "<Occupied".chars() {
if c != ch {return Ok(None);}
let status = inp.read(&mut byte)?;
if status == 0 {return Ok(None);}
ch = byte[0] as char;
}
let trainnum: String = match ReadQuotedString(inp)? {
None => {return Ok(None);},
Some(s) => s,
};
let from: f64 = match ReadF64(inp)? {
None => {return Ok(None);},
Some(f) => f,
};
let status = inp.read(&mut byte)?;
if status == 0 {return Ok(None);}
ch = byte[0] as char;
if ch != ':' {
return Err(Error::new(ErrorKind::Other,"Syntax error: missing ':'"));
}
let until: f64 = match ReadF64(inp)? {
None => {return Ok(None);},
Some(u) => u,
};
let trainnum2: String = match ReadQuotedString(inp)? {
None => {return Ok(None);},
Some(s) => s,
};
loop {
let status = inp.read(&mut byte)?;
if status == 0 {return Ok(None);}
ch = byte[0] as char;
match ch {
'>' => {return Ok(Some(Self::new(trainnum,from,until,trainnum2)));},
' '|'\t'|'\n' => {continue;},
_ => {return Err(Error::new(ErrorKind::Other,"Syntax error: missing '>'"));},
};
}
}
}
#[derive(Default, Debug, Clone, Copy)]
pub struct TimeRange {
from: f64,
to: f64,
}
impl PartialEq for TimeRange {
fn eq(&self, other: &Self) -> bool {
self.to == other.to && self.from == other.from
}
}
impl Ord for TimeRange {
fn cmp(&self, other: &Self) -> Ordering {
if self.to <= other.from {
return Ordering::Less;
} else if self.from >= other.to {
return Ordering::Greater;
} else {
return Ordering::Equal;
}
}
}
impl PartialOrd for TimeRange {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
fn lt(&self, other: &Self) -> bool {
self.to <= other.from
}
fn gt(&self, other: &Self) -> bool {
self.from >= other.to
}
}
impl Eq for TimeRange { }
impl fmt::Display for TimeRange {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "<TimeRange {:4.2} {:4.2}>", self.from, self.to)
}
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum TimeRangeParseError {
StartSyntaxError,
FromSyntaxError,
ToSyntaxError,
ExtraCharacters,
}
impl fmt::Display for TimeRangeParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TimeRangeParseError::StartSyntaxError =>
write!(f, "Missing '<TimeRange '"),
TimeRangeParseError::FromSyntaxError =>
write!(f, "Missing from"),
TimeRangeParseError::ToSyntaxError =>
write!(f, "Missing to"),
TimeRangeParseError::ExtraCharacters =>
write!(f, "Extra trailing characters"),
}
}
}
impl FromStr for TimeRange {
type Err = TimeRangeParseError;
fn from_str(string: &str) -> Result<Self, Self::Err> {
let (result, endpos) = Self::ParseTimeRange(string)?;
if endpos == string.len() {
Ok(result)
} else {
Err(TimeRangeParseError::ExtraCharacters)
}
}
}
impl TimeRange {
pub fn new(from_: f64, to_: f64) -> Self {
assert!(from_ < to_,"Backwars time tange!");
Self { from: from_, to: to_ }
}
pub fn From (&self) -> f64 {self.from}
pub fn To (&self) -> f64 {self.to}
pub fn ContainsTime(&self, time: f64 ) -> bool {
time >= self.from && time <= self.to
}
pub fn ParseTimeRange(string: &str) -> Result<(Self, usize), TimeRangeParseError> {
let mut pos: usize;
let from: f64;
let to: f64;
match string.match_indices("<TimeRange").next() {
None => return Err(TimeRangeParseError::StartSyntaxError),
Some((n, m)) => pos = n + m.len(),
};
while string[pos..pos+1] == *" " {
pos += 1;
}
match string[pos..].match_indices(' ').next() {
None => return Err(TimeRangeParseError::FromSyntaxError),
Some((n, m)) => {
from = match (string[pos..n+pos].trim()).parse::<f64>() {
Ok(f) => f,
Err(p) => return Err(TimeRangeParseError::FromSyntaxError),
};
pos += n + m.len();},
};
while string[pos..pos+1] == *" " {
pos += 1;
}
match string[pos..].match_indices('>').next() {
None => return Err(TimeRangeParseError::ToSyntaxError),
Some((n, m)) => {
to = match (string[pos..n+pos].trim()).parse::<f64>() {
Ok(t) => t,
Err(p) => return Err(TimeRangeParseError::ToSyntaxError),
};
pos += n + m.len();
},
};
Ok((Self { from: from, to: to }, pos))
}
pub fn Write(&self,f: &mut BufWriter<File>) -> std::io::Result<()> {
write!(f,"<TimeRange {:5.3}:{:5.3}>",self.from,self.to)
}
}
pub type OccupiedMap = BTreeMap<TimeRange, Occupied>;
#[derive(Default, Debug, Clone, PartialEq)]
pub struct StorageTrack {
name: String,
occupations: OccupiedMap,
}
impl fmt::Display for StorageTrack {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "<StorageTrack \"{}\" {} ",self.name,
self.occupations.len())?;
for (tr, occ) in self.occupations.iter() {
write!(f,"{} {} ",tr,occ)?;
}
write!(f,">")
}
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum StorageTrackParseError {
StartSyntaxError,
NameSyntaxError,
CountSyntaxError,
MissingTimeRangeSyntaxError,
MissingOccupiedSyntaxError,
ExtraCharacters,
}
impl fmt::Display for StorageTrackParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
StorageTrackParseError::StartSyntaxError =>
write!(f, "Missing '<StorageTrack '"),
StorageTrackParseError::NameSyntaxError =>
write!(f, "Missing name"),
StorageTrackParseError::CountSyntaxError =>
write!(f, "Missing occupations count"),
StorageTrackParseError::MissingTimeRangeSyntaxError =>
write!(f, "Missing time range"),
StorageTrackParseError::MissingOccupiedSyntaxError =>
write!(f, "Missing occupied"),
StorageTrackParseError::ExtraCharacters =>
write!(f, "Extra trailing characters"),
}
}
}
impl FromStr for StorageTrack {
type Err = StorageTrackParseError;
fn from_str(string: &str) -> Result<Self, Self::Err> {
let (result,pos) = Self::ParseStorageTrack(string)?;
if pos == string.len() {
Ok(result)
} else {
Err(StorageTrackParseError::ExtraCharacters)
}
}
}
impl StorageTrack {
pub fn new (name_: String) -> Self {
Self {name: name_.clone(), occupations: BTreeMap::new(),}
}
pub fn Name(&self) -> String {self.name.clone()}
pub fn SetName(&mut self, name_: String) {
self.name = name_.clone();
}
pub fn IncludesTime(&self, time: f64) -> Option<&Occupied> {
for (tr, occ) in self.occupations.iter() {
if time > tr.To() {continue;}
if tr.ContainsTime(time) {return Some(occ);}
if time < tr.From() {break;}
}
None
}
pub fn StoreTrain (&mut self, train: String, from: f64, to: f64,
train2: String) -> Option<&Occupied> {
let range = TimeRange::new(from,to);
let newOccupied = Occupied::new(train,from,to,train2);
self.occupations.insert(range,newOccupied);
self.occupations.get(&range)
}
pub fn RemovedStoredTrain (&mut self, from: f64, to: f64) -> bool {
let range = TimeRange::new(from,to);
if self.occupations.contains_key(&range) {
self.occupations.remove(&range);
true
} else {
false
}
}
pub fn UsedTimeRange(&self, from: f64, to: f64) -> bool {
for (tr, occ) in self.occupations.iter() {
if from > tr.To() {break;}
if to < tr.From() {continue;}
if tr.ContainsTime(from) ||
tr.ContainsTime(to) {
return true;
}
}
false
}
pub fn FindOccupied(&self, from: f64, to: f64) -> Option<&Occupied> {
self.occupations.get(&TimeRange::new(from,to))
}
pub fn UpdateStoredTrain(&mut self, from: f64, to: f64, train: String) -> Option<&Occupied> {
let range = TimeRange::new(from,to);
match self.occupations.get(&range) {
None => None,
Some(occ) => {
let newOccupied = Occupied::new(train,from,to,occ.TrainNum2());
self.occupations.insert(range,newOccupied);
self.occupations.get(&range)
},
}
}
pub fn UpdateStoredTrain2(&mut self, from: f64, to: f64, train: String) -> Option<&Occupied> {
let range = TimeRange::new(from,to);
match self.occupations.get(&range) {
None => None,
Some(occ) => {
let newOccupied = Occupied::new(occ.TrainNum(),from,to,train);
self.occupations.insert(range,newOccupied);
self.occupations.get(&range)
},
}
}
pub fn UpdateStoredTrainArrival(&mut self, from: f64, to: f64,
newArrival: f64) -> Option<&Occupied> {
let range = TimeRange::new(from,to);
match self.occupations.get(&range) {
None => None,
Some(occ) => {
let newOccupied = Occupied::new(occ.TrainNum(),newArrival,range.To(),occ.TrainNum2());
self.occupations.remove(&range);
let newrange = TimeRange::new(newArrival,to);
self.occupations.insert(newrange,newOccupied);
self.occupations.get(&newrange)
},
}
}
pub fn UpdateStoredTrainDeparture(&mut self, from: f64, to: f64,
newDeparture: f64) -> Option<&Occupied> {
let range = TimeRange::new(from,to);
match self.occupations.get(&range) {
None => None,
Some(occ) => {
let newOccupied = Occupied::new(occ.TrainNum(),range.From(),newDeparture,occ.TrainNum2());
self.occupations.remove(&range);
let newrange = TimeRange::new(from,newDeparture);
self.occupations.insert(newrange,newOccupied);
self.occupations.get(&newrange)
},
}
}
pub fn ParseStorageTrack(string: &str) -> Result<(Self, usize), StorageTrackParseError> {
let mut pos: usize;
let name: String;
let count: usize;
match string.match_indices("<StorageTrack \"").next() {
None => return Err(StorageTrackParseError::StartSyntaxError),
Some((n, m)) => pos = n + m.len(),
};
match string[pos..].match_indices('"').next() {
None => return Err(StorageTrackParseError::NameSyntaxError),
Some((n, m)) => {
name = String::from(&string[pos..n+pos]);
pos += n + m.len();
},
};
let mut result = StorageTrack::new(name);
while string[pos..pos+1] == *" " || string[pos..pos+1] == *"\t" ||
string[pos..pos+1] == *"\n" {
pos += 1;
}
match string[pos..].match_indices(' ').next() {
None => return Err(StorageTrackParseError::CountSyntaxError),
Some((n, m)) => {
count = match (string[pos..n+pos].trim()).parse::<usize>() {
Ok(c) => c,
Err(p) => return Err(StorageTrackParseError::CountSyntaxError),
};
pos += n + m.len();
},
};
for i in 0..count {
while string[pos..pos+1] == *" " || string[pos..pos+1] == *"\t" ||
string[pos..pos+1] == *"\n" {
pos += 1;
};
let timerange = match TimeRange::ParseTimeRange(&string[pos..]) {
Ok((t,p)) => {
pos += p;
t
},
Err(p) => return Err(StorageTrackParseError::MissingTimeRangeSyntaxError),
};
while string[pos..pos+1] == *" " || string[pos..pos+1] == *"\t" ||
string[pos..pos+1] == *"\n" {
pos += 1;
};
let occupued = match Occupied::ParseOccupied(&string[pos..]) {
Ok((o,p)) => {
pos += p;
o
},
Err(p) => return Err(StorageTrackParseError::MissingOccupiedSyntaxError),
};
result.occupations.insert(timerange,occupued);
}
while string[pos..pos+1] == *" " || string[pos..pos+1] == *"\t" ||
string[pos..pos+1] == *"\n" {
pos += 1;
};
if string[pos..pos+1] != *">" {
Err(StorageTrackParseError::ExtraCharacters)
} else {
Ok((result,pos+1))
}
}
pub fn iter(&self) -> Iter<'_, TimeRange, Occupied> {
self.occupations.iter()
}
pub fn iter_mut(&mut self) -> IterMut<'_, TimeRange, Occupied> {
self.occupations.iter_mut()
}
pub fn occupations(&self) -> Values<'_, TimeRange, Occupied> {
self.occupations.values()
}
pub fn occupations_mut(&mut self) -> ValuesMut<'_, TimeRange, Occupied> {
self.occupations.values_mut()
}
pub fn Write(&self,f: &mut BufWriter<File>) -> std::io::Result<()> {
writeln!(f,"<StorageTrack \"{}\" {} ",self.name,self.occupations.len())?;
for (tr,occ) in self.occupations.iter() {
tr.Write(f)?;
write!(f," ")?;
occ.Write(f)?;
}
write!(f,">")
}
pub fn Read(inp: &mut BufReader<File>) -> std::io::Result<Option<Self>> {
let mut ch: char;
let mut byte: [u8; 1] = [0; 1];
loop {
let status = inp.read(&mut byte)?;
if status == 0 {return Ok(None);}
ch = byte[0] as char;
match ch {
' '|'\t'|'\n' => (),
_ => {break;},
}
}
for c in "<StorageTrack".chars() {
if c != ch {return Ok(None);}
let status = inp.read(&mut byte)?;
if status == 0 {return Ok(None);}
ch = byte[0] as char;
}
let name: String = match ReadQuotedString(inp)? {
None => {return Ok(None);},
Some(s) => s,
};
let mut this = Self {name: name, occupations: BTreeMap::new(),};
let count: usize = match ReadUSize(inp)? {
None => {return Ok(None);},
Some(c) => c,
};
for i in 0..count {
let temp: Occupied = match Occupied::Read(inp)? {
None => {return Ok(None);},
Some(occ) => occ,
};
this.occupations.insert(TimeRange::new(temp.From(),temp.Until()),
temp);
}
loop {
let status = inp.read(&mut byte)?;
if status == 0 {return Ok(None);}
ch = byte[0] as char;
match ch {
'>' => {return Ok(Some(this));},
' '|'\t'|'\n' => {continue;},
_ => {return Err(Error::new(ErrorKind::Other,"Syntax error: missing '>'"));},
};
}
}
}
pub type StorageTrackMap = BTreeMap<String, StorageTrack>;
#[derive(Default, Debug, Clone, PartialEq)]
pub struct Station {
name: String,
storageTracks: StorageTrackMap,
smile: f64,
duplicateStationIndex: Option<usize>,
}
impl fmt::Display for Station {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "<Station \"{}\" {:5.3} {} {}", self.name, self.smile,
match self.duplicateStationIndex {
None => String::from("-1"),
Some(u) => format!("{}",u),
}, self.storageTracks.len())?;
for (n, st) in self.storageTracks.iter() {
write!(f," \"{}\" {}",n,st)?;
}
write!(f,">")
}
}
#[derive(Debug)]
pub enum StationParseError {
StartSyntaxError,
NameSyntaxError,
SmileSyntaxError,
CountSyntaxError,
DuplSyntaxError,
STNameSyntaxError,
STrackSyntaxError(StorageTrackParseError),
ExtraCharacters,
MissingBracket,
}
impl From<StorageTrackParseError> for StationParseError {
fn from(error: StorageTrackParseError) -> Self {
StationParseError::STrackSyntaxError(error)
}
}
impl fmt::Display for StationParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
StationParseError::StartSyntaxError =>
write!(f,"Missing '<Station '"),
StationParseError::NameSyntaxError =>
write!(f,"Missing station name"),
StationParseError::SmileSyntaxError =>
write!(f,"Missing SMile"),
StationParseError::CountSyntaxError =>
write!(f,"Missing Storage track Count"),
StationParseError::DuplSyntaxError =>
write!(f,"Missing duplicate station index"),
StationParseError::STNameSyntaxError =>
write!(f,"Missing Storage track name"),
StationParseError::STrackSyntaxError(e) =>
write!(f,"Missing StorageTrack: {}",e.to_string()),
StationParseError::ExtraCharacters =>
write!(f,"Extra characters"),
StationParseError::MissingBracket =>
write!(f,"Missing '>'"),
}
}
}
impl FromStr for Station {
type Err = StationParseError;
fn from_str(string: &str) -> Result<Self, Self::Err> {
let (result,pos) = Station::ParseStation(string)?;
if pos == string.len() {
Ok(result)
} else {
Err(StationParseError::ExtraCharacters)
}
}
}
impl Station {
pub fn new(name_: String, smile_: f64) -> Self {
Self {name: name_, smile: smile_, duplicateStationIndex: None,
storageTracks: BTreeMap::new() }
}
pub fn Name(&self) -> String {self.name.clone()}
pub fn SMile(&self) -> f64 {self.smile}
pub fn DuplicateStationIndex(&self) -> Option<usize> {self.duplicateStationIndex}
pub fn SetDuplicateStationIndex(&mut self, index: Option<usize>) {
self.duplicateStationIndex = index;
}
pub fn AddStorageTrack(&mut self, name_: &String) -> Option<&mut StorageTrack> {
if self.FindStorageTrack(name_).is_some() {return None;}
let newtrack = StorageTrack::new(name_.to_string());
self.storageTracks.insert(name_.to_string(),newtrack);
self.storageTracks.get_mut(name_)
}
pub fn FindStorageTrack(&self,name: &String) -> Option<&StorageTrack> {
self.storageTracks.get(name)
}
pub fn FindStorageTrack_mut(&mut self,name: &String) -> Option<&mut StorageTrack> {
self.storageTracks.get_mut(name)
}
pub fn FindTrackTrainIsStoredOn(&self,trainNumber: String, fromtime: f64,
totime: f64) -> Option<&StorageTrack> {
for (name, ST) in self.storageTracks.iter() {
let mut occupied = ST.IncludesTime(fromtime);
match occupied {
None => (),
Some(occ) => if occ.TrainNum() == trainNumber {return Some(ST);},
};
occupied = ST.IncludesTime(totime);
match occupied {
None => (),
Some(occ) => if occ.TrainNum() == trainNumber {return Some(ST);},
};
}
None
}
pub fn FindTrackTrainIsStoredOn_mut(&mut self,trainNumber: String,
fromtime: f64,totime: f64) -> Option<&mut StorageTrack> {
for (name, ST) in self.storageTracks.iter_mut() {
let mut occupied = ST.IncludesTime(fromtime);
match occupied {
None => (),
Some(occ) => if occ.TrainNum() == trainNumber {return Some(ST);},
};
occupied = ST.IncludesTime(totime);
match occupied {
None => (),
Some(occ) => if occ.TrainNum() == trainNumber {return Some(ST);},
};
}
None
}
pub fn NumberOfStorageTracks(&self) -> usize {self.storageTracks.len()}
pub fn iter(&self) -> Iter<'_, String, StorageTrack> {
self.storageTracks.iter()
}
pub fn iter_mut(&mut self) -> IterMut<'_, String, StorageTrack> {
self.storageTracks.iter_mut()
}
pub fn storagetracks(&self) -> Values<'_, String, StorageTrack> {
self.storageTracks.values()
}
pub fn storagetracks_mut(&mut self) -> ValuesMut<'_, String, StorageTrack> {
self.storageTracks.values_mut()
}
pub fn ParseStation(string: &str) -> Result<(Self, usize), StationParseError> {
let mut pos: usize;
match string.match_indices("<Station \"").next() {
None => return Err(StationParseError::StartSyntaxError),
Some((n, m)) => pos = n + m.len(),
}
let name: String;
match string[pos..].match_indices('"').next() {
None => return Err(StationParseError::NameSyntaxError),
Some((n, m)) => {
name = String::from(&string[pos..n+pos]);
pos += n + m.len();
},
};
while string[pos..pos+1] == *" " || string[pos..pos+1] == *"\t" ||
string[pos..pos+1] == *"\n" {
pos += 1;
}
let smile: f64;
match string[pos..].match_indices(' ').next() {
None => return Err(StationParseError::SmileSyntaxError),
Some((n, m)) => {
smile = match (string[pos..n+pos].trim()).parse::<f64>() {
Ok(sm) => sm,
Err(p) => return Err(StationParseError::SmileSyntaxError),
};
pos += n + m.len();
},
};
let mut result = Station::new(name,smile);
while string[pos..pos+1] == *" " || string[pos..pos+1] == *"\t" ||
string[pos..pos+1] == *"\n" {
pos += 1;
}
let dupl: Option<usize>;
match string[pos..].match_indices(' ').next() {
None => return Err(StationParseError::DuplSyntaxError),
Some((n, m)) => {
let temp = string[pos..n+pos].trim();
pos += n+m.len();
if temp == "-1" {
dupl = None;
} else {
let d = match temp.parse::<usize>() {
Ok(x) => x,
Err(p) =>
return Err(StationParseError::DuplSyntaxError),
};
dupl = Some(d);
};
}
};
result.SetDuplicateStationIndex(dupl);
while string[pos..pos+1] == *" " || string[pos..pos+1] == *"\t" ||
string[pos..pos+1] == *"\n" {
pos += 1;
}
let count: usize;
match string[pos..].match_indices(&[' ','>']).next() {
None => return Err(StationParseError::CountSyntaxError),
Some((n, m)) => {
count = match (string[pos..n+pos].trim()).parse::<usize>() {
Ok(sm) => sm,
Err(p) => return Err(StationParseError::CountSyntaxError),
};
pos += n + m.len();
},
};
for i in 0..count {
while string[pos..pos+1] == *" " || string[pos..pos+1] == *"\t" ||
string[pos..pos+1] == *"\n" {
pos += 1;
}
let track: StorageTrack = match StorageTrack::ParseStorageTrack(&string[pos..]) {
Ok((st,p)) => {
pos += p;
st
},
Err(p) => return Err(StationParseError::from(p)),
};
result.storageTracks.insert(track.Name(),track);
}
match string[pos..].match_indices('>').next() {
None => return Err(StationParseError::MissingBracket),
Some((n, m)) => pos += n + m.len(),
}
Ok((result,pos))
}
pub fn Write(&self,f: &mut BufWriter<File>) -> std::io::Result<()> {
write!(f,"<Station \"{}\" {:5.3} ",self.name,self.smile)?;
match self.duplicateStationIndex {
None => {write!(f,"-1 ")?;},
Some(d) => {write!(f,"{} ",d)?;},
};
writeln!(f,"{} ",self.storageTracks.len())?;
for st in self.storageTracks.values() {
st.Write(f)?;
}
write!(f,">")
}
pub fn Read(inp: &mut BufReader<File>) -> std::io::Result<Option<Self>> {
let mut ch: char;
let mut byte: [u8; 1] = [0; 1];
loop {
let status = inp.read(&mut byte)?;
if status == 0 {return Ok(None);}
ch = byte[0] as char;
match ch {
' '|'\t'|'\n' => (),
_ => {break;},
}
}
for c in "<Station".chars() {
if c != ch {return Ok(None);}
let status = inp.read(&mut byte)?;
if status == 0 {return Ok(None);}
ch = byte[0] as char;
}
let name: String = match ReadQuotedString(inp)? {
None => {return Ok(None);},
Some(s) => s,
};
let smile: f64 = match ReadF64(inp)? {
None => {return Ok(None);},
Some(f) => f,
};
let dupl: Option<usize> = match ReadISize(inp)? {
None => {return Ok(None);},
Some(-1) => None,
Some(d) if d >= 0 => Some(d as usize),
_ => {return Ok(None);},
};
let count: usize = match ReadUSize(inp)? {
None => {return Ok(None);},
Some(c) => c,
};
let mut this = Self {name: name, smile: smile,
duplicateStationIndex: dupl,
storageTracks: BTreeMap::new() };
for i in 0..count {
let temp: StorageTrack = match StorageTrack::Read(inp)? {
None => {return Ok(None);},
Some(st) => st,
};
this.storageTracks.insert(temp.Name(),temp);
}
loop {
let status = inp.read(&mut byte)?;
if status == 0 {return Ok(None);}
ch = byte[0] as char;
match ch {
'>' => {return Ok(Some(this));},
' '|'\t'|'\n' => {continue;},
_ => {return Err(Error::new(ErrorKind::Other,"Syntax error: missing '>'"));},
};
}
}
}
pub type StationVector = Vec<Station>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn Occupied_from_str () {
let temp = "<Occupied \"train1\" 4.10:5.20 \"\">";
let result = Occupied::from_str(temp);
assert_eq!(result,Ok(Occupied::new(String::from("train1"), 4.1, 5.2, String::from(""))));
}
#[test]
fn Occupied_Display() {
let temp = Occupied::new(String::from("train1"), 4.1, 5.2, String::from(""));
let out = format!("{}",temp);
assert_eq!(out,String::from("<Occupied \"train1\" 4.10:5.20 \"\">"));
}
#[test]
fn Occupied_TrainNum2 () {
let temp = Occupied::new(String::from("train1"), 4.0, 5.0, String::from(""));
assert_eq!(temp.TrainNum2(),String::from(""));
}
#[test]
fn Occupied_Until () {
let temp = Occupied::new(String::from("train1"), 4.0, 5.0, String::from(""));
assert_eq!(temp.Until(),5.0);
}
#[test]
fn Occupied_From () {
let temp = Occupied::new(String::from("train1"), 4.0, 5.0, String::from(""));
assert_eq!(temp.From(),4.0);
}
#[test]
fn Occupied_TrainNum() {
let temp = Occupied::new(String::from("train1"), 4.0, 5.0, String::from(""));
assert_eq!(temp.TrainNum(),String::from("train1"));
}
#[test]
fn Occupied_new() {
let result = Occupied::new(String::from("train1"), 4.5, 4.75,
String::from(""));
let temp = Occupied { trainnum: String::from("train1"),
from: 4.5,
until: 4.75,
trainnum2: String::from("") };
assert_eq!(result,temp);
}
#[test]
fn TimeRange_new () {
let result = TimeRange::new(5.1, 6.2);
let temp = TimeRange { from: 5.1, to: 6.2 };
assert_eq!(result,temp);
}
#[test]
fn TimeRange_To () {
let result = TimeRange::new(5.1, 6.2);
assert_eq!(result.To(),6.2);
}
#[test]
fn TimeRange_From () {
let result = TimeRange::new(5.1, 6.2);
assert_eq!(result.From(),5.1);
}
#[test]
fn TimeRange_ContainsTimeIn() {
let result = TimeRange::new(5.1, 6.2);
assert_eq!(result.ContainsTime(6.0),true);
}
#[test]
fn TimeRange_ContainsTimeOut() {
let result = TimeRange::new(5.1, 6.2);
assert_eq!(result.ContainsTime(7.0),false);
}
#[test]
fn TimeRange_Eq_ab() {
let a = TimeRange::new(2.4, 4.2);
let b = TimeRange::new(2.4, 4.2);
assert_eq!(a == b,true);
}
#[test]
fn TimeRange_Eq_ba() {
let a = TimeRange::new(2.4, 4.2);
let b = TimeRange::new(2.4, 4.2);
assert_eq!(b == b,true);
}
#[test]
fn TimeRange_Ne_ab() {
let a = TimeRange::new(2.4, 4.2);
let b = TimeRange::new(2.4, 4.2);
assert_eq!(a != b,false);
}
#[test]
fn TimeRange_Ne_ba() {
let a = TimeRange::new(2.4, 4.2);
let b = TimeRange::new(2.4, 4.2);
assert_eq!(b != a,false);
}
#[test]
fn TimeRange_Lt_ab() {
let a = TimeRange::new(2.4, 4.2);
let b = TimeRange::new(4.7, 5.9);
assert_eq!(a < b,true);
}
#[test]
fn TimeRange_Gt_ba() {
let a = TimeRange::new(2.4, 4.2);
let b = TimeRange::new(4.7, 5.9);
assert_eq!(b > a,true);
}
#[test]
fn TimeRange_NotLt_ba() {
let a = TimeRange::new(2.4, 4.2);
let b = TimeRange::new(4.7, 5.9);
assert_eq!(b < a,false);
}
#[test]
fn TimeRange_NotGt_ab() {
let a = TimeRange::new(2.4, 4.2);
let b = TimeRange::new(4.7, 5.9);
assert_eq!(a > b,false);
}
#[test]
fn TimeRange_Display() {
let temp = TimeRange::new(4.1, 5.2);
let out = format!("{}",temp);
assert_eq!(out,String::from("<TimeRange 4.10 5.20>"));
}
#[test]
fn TimeRange_from_str () {
let temp = "<TimeRange 4.10 5.20>";
let result = TimeRange::from_str(temp);
assert_eq!(result,Ok(TimeRange::new(4.1, 5.2)));
}
#[test]
fn StorageTrack_new () {
let track = StorageTrack::new(String::from("Tract 1"));
assert_eq!(track,StorageTrack{name: String::from("Tract 1"),
occupations: BTreeMap::new()});
}
#[test]
fn StorageTrack_Name () {
let track = StorageTrack::new(String::from("Tract 1"));
assert_eq!(track.Name(),String::from("Tract 1"));
}
#[test]
fn StorageTrack_SetName () {
let mut track = StorageTrack::new(String::from("Tract 1"));
track.SetName(String::from("Track 1"));
assert_eq!(track.Name(),String::from("Track 1"));
}
#[test]
fn StorageTrack_StoreTrain () {
let mut track = StorageTrack::new(String::from("Track 1"));
let result = track.StoreTrain(String::from("Train1"),4.2, 5.1, String::from(""));
assert_eq!(result,Some(&Occupied::new(String::from("Train1"),4.2, 5.1, String::from(""))));
}
#[test]
fn StorageTrack_IncludesTime() {
let mut track = StorageTrack::new(String::from("Track 1"));
let result = track.StoreTrain(String::from("Train1"),4.2, 5.1, String::from(""));
let includes = track.IncludesTime(5.0);
assert_eq!(includes,Some(&Occupied::new(String::from("Train1"),4.2, 5.1, String::from(""))));
}
#[test]
fn StorageTrack_RemovedStoredTrain_true() {
let mut track = StorageTrack::new(String::from("Track 1"));
let result = track.StoreTrain(String::from("Train1"),4.2, 5.1, String::from(""));
assert_eq!(track.RemovedStoredTrain(4.2, 5.1),true);
}
#[test]
fn StorageTrack_RemovedStoredTrain_false() {
let mut track = StorageTrack::new(String::from("Track 1"));
let result = track.StoreTrain(String::from("Train1"),4.2, 5.1, String::from(""));
assert_eq!(track.RemovedStoredTrain(2.4, 3.0),false);
}
#[test]
fn StorageTrack_UsedTimeRange_true() {
let mut track = StorageTrack::new(String::from("Track 1"));
let result = track.StoreTrain(String::from("Train1"),4.2, 5.1, String::from(""));
assert_eq!(track.UsedTimeRange(4.2, 5.1),true);
}
#[test]
fn StorageTrack_UsedTimeRange_false() {
let mut track = StorageTrack::new(String::from("Track 1"));
let result = track.StoreTrain(String::from("Train1"),4.2, 5.1, String::from(""));
assert_eq!(track.UsedTimeRange(3.2, 4.0),false);
}
#[test]
fn StorageTrack_FindOccupied() {
let mut track = StorageTrack::new(String::from("Track 1"));
let result = track.StoreTrain(String::from("Train1"),4.2, 5.1, String::from(""));
assert_eq!(track.FindOccupied(4.2, 5.1),Some(&Occupied::new(String::from("Train1"),4.2, 5.1, String::from(""))));
}
#[test]
fn StorageTrack_UpdateStoredTrain () {
let mut track = StorageTrack::new(String::from("Track 1"));
let result = track.StoreTrain(String::from("Train1"),4.2, 5.1, String::from(""));
assert_eq!(track.UpdateStoredTrain(4.2, 5.1, String::from("OtherTrain")),
Some(&Occupied::new(String::from("OtherTrain"),4.2, 5.1, String::from(""))));
}
#[test]
fn StorageTrack_UpdateStoredTrain2 () {
let mut track = StorageTrack::new(String::from("Track 1"));
let result = track.StoreTrain(String::from("Train1"),4.2, 5.1, String::from(""));
assert_eq!(track.UpdateStoredTrain2(4.2, 5.1, String::from("OtherTrain")),
Some(&Occupied::new(String::from("Train1"),4.2, 5.1, String::from("OtherTrain"))));
}
#[test]
fn StorageTrack_UpdateStoredTrainArrival () {
let mut track = StorageTrack::new(String::from("Track 1"));
let result = track.StoreTrain(String::from("Train1"),4.2, 5.1, String::from(""));
assert_eq!(track.UpdateStoredTrainArrival(4.2, 5.1, 5.0),
Some(&Occupied::new(String::from("Train1"),5.0, 5.1, String::from(""))));
}
#[test]
fn StorageTrack_UpdateStoredTrainDeparture () {
let mut track = StorageTrack::new(String::from("Track 1"));
let result = track.StoreTrain(String::from("Train1"),4.2, 5.1, String::from(""));
assert_eq!(track.UpdateStoredTrainDeparture(4.2, 5.1, 5.0),
Some(&Occupied::new(String::from("Train1"),4.2, 5.0, String::from(""))));
}
#[test]
fn StorageTrack_Display () {
let mut track = StorageTrack::new(String::from("Track 1"));
let result = track.StoreTrain(String::from("Train1"),4.2, 5.1, String::from(""));
let formatted = format!("{}",track);
assert_eq!(formatted,
String::from("<StorageTrack \"Track 1\" 1 <TimeRange 4.20 5.10> <Occupied \"Train1\" 4.20:5.10 \"\"> >"));
}
#[test]
fn StorageTrack_from_str () {
let track =
match StorageTrack::from_str("<StorageTrack \"Track 1\" 1 <TimeRange 4.20 5.10> <Occupied \"Train1\" 4.20:5.10 \"\"> >") {
Err(p) => panic!("{}",p.to_string()),
Ok(t) => t,
};
let formatted = format!("{}",track);
assert_eq!(formatted,
String::from("<StorageTrack \"Track 1\" 1 <TimeRange 4.20 5.10> <Occupied \"Train1\" 4.20:5.10 \"\"> >"));
}
#[test]
fn Station_new () {
let station = Station::new(String::from("Station 1"), 45.7);
assert_eq!(station, Station { name: String::from("Station 1"),
storageTracks: BTreeMap::new(),
smile: 45.7,
duplicateStationIndex: None });
}
#[test]
fn Station_Name () {
let station = Station::new(String::from("Station 1"), 45.7);
assert_eq!(station.Name(),String::from("Station 1"));
}
#[test]
fn Station_SMile () {
let station = Station::new(String::from("Station 1"), 45.7);
assert_eq!(station.SMile(),45.7);
}
#[test]
fn Station_DuplicateStationIndex () {
let station = Station::new(String::from("Station 1"), 45.7);
assert_eq!(station.DuplicateStationIndex().is_none(),true);
}
#[test]
fn Station_SetDuplicateStationIndex () {
let mut station = Station::new(String::from("Station 1"), 45.7);
station.SetDuplicateStationIndex(Some(42));
assert_eq!(station.DuplicateStationIndex(),Some(42));
}
#[test]
fn Station_AddStorageTrack () {
let mut station = Station::new(String::from("Station 1"), 45.7);
let st = station.AddStorageTrack(&String::from("Track 1"));
assert_eq!(st,Some(&mut StorageTrack::new(String::from("Track 1"))));
}
#[test]
fn Station_FindStorageTrack () {
let mut station = Station::new(String::from("Station 1"), 45.7);
station.AddStorageTrack(&String::from("Track 1"));
assert_eq!(station.FindStorageTrack(&String::from("Track 1")),
Some(&StorageTrack::new(String::from("Track 1"))));
}
#[test]
fn Station_FindStorageTrack_mut () {
let mut station = Station::new(String::from("Station 1"), 45.7);
station.AddStorageTrack(&String::from("Track 1"));
assert_eq!(station.FindStorageTrack_mut(&String::from("Track 1")),
Some(&mut StorageTrack::new(String::from("Track 1"))));
}
#[test]
fn Station_FindTrackTrainIsStoredOn () {
let mut station = Station::new(String::from("Station 1"), 45.7);
let track = station.AddStorageTrack(&String::from("Track 1")).unwrap();
track.StoreTrain(String::from("Train1"),4.2,5.1,String::from(""));
let other = track.clone();
let thetrack = station.FindTrackTrainIsStoredOn(String::from("Train1"),4.2,5.1).unwrap();
assert_eq!(thetrack.Name(),String::from("Track 1"));
assert_eq!(*thetrack,other);
}
#[test]
fn Station_FindTrackTrainIsStoredOn_mut () {
let mut station = Station::new(String::from("Station 1"), 45.7);
let track = station.AddStorageTrack(&String::from("Track 1")).unwrap();
track.StoreTrain(String::from("Train1"),4.2,5.1,String::from(""));
let other = track.clone();
let thetrack = station.FindTrackTrainIsStoredOn_mut(String::from("Train1"),4.2,5.1).unwrap();
assert_eq!(thetrack.Name(),String::from("Track 1"));
assert_eq!(*thetrack,other);
}
#[test]
fn Station_NumberOfStorageTracks () {
let mut station = Station::new(String::from("Station 1"), 45.7);
station.AddStorageTrack(&String::from("Track 1"));
assert_eq!(station.NumberOfStorageTracks(),1);
}
#[test]
fn Station_Display () {
let mut station = Station::new(String::from("Station 1"), 45.7);
let track = station.AddStorageTrack(&String::from("Track 1")).unwrap();
track.StoreTrain(String::from("Train1"),4.2,5.1,String::from(""));
let output = format!("{}",station);
assert_eq!(output,String::from("<Station \"Station 1\" 45.700 None 1 \"Track 1\" <StorageTrack \"Track 1\" 1 <TimeRange 4.20 5.10> <Occupied \"Train1\" 4.20:5.10 \"\"> >>"));
}
#[test]
fn Station_from_str () {
let mut station = Station::new(String::from("Station 1"), 45.7);
let track = station.AddStorageTrack(&String::from("Track 1")).unwrap();
track.StoreTrain(String::from("Train1"),4.2,5.1,String::from(""));
let output = format!("{}",station);
let otherstation = match Station::from_str(&output) {
Ok(s) => s,
Err(p) => panic!("{}", p.to_string()),
};
assert_eq!(station,otherstation);
}
}