use std::{
collections::BTreeMap,
fmt::{self, Display, Formatter},
fs::File,
io::{BufRead, BufReader, Error as IoError},
num::ParseIntError,
path::Path,
str::{Chars, FromStr},
};
use chrono::NaiveDate;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum Error {
#[error("IO error: {0}")]
Io(#[from] IoError),
#[error("{0}")]
ParseInt(#[from] std::num::ParseIntError),
#[error("Invalid type: {0}")]
InvalidType(u8),
#[error("Invalid Textkennzeichen: {0}")]
InvalidTextkennzeichen(u8),
}
pub struct FieldReader<'a> {
it: Chars<'a>,
}
impl<'a> FieldReader<'a> {
pub fn new(buf: &'a str) -> Self {
FieldReader { it: buf.chars() }
}
pub fn next(&mut self, n: usize) -> &str {
let s = self.it.as_str();
let mut nb = 0;
for _ in 0..n {
if let Some(c) = self.it.next() {
nb += c.len_utf8();
} else {
break;
}
}
&s[0..nb]
}
pub fn parse_next<T: FromStr>(&mut self, n: usize) -> Result<T, <T as FromStr>::Err> {
self.next(n).parse()
}
pub fn skip(&mut self, n: usize) {
for _ in 0..n {
self.it.next();
}
}
}
pub struct Parser<R> {
reader: R,
}
impl Parser<BufReader<File>> {
pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self, IoError> {
let reader = BufReader::new(File::open(path)?);
Ok(Self::new(reader))
}
}
impl<R: BufRead> Iterator for Parser<R> {
type Item = Result<Record, Error>;
fn next(&mut self) -> Option<Self::Item> {
self.parse_line().transpose()
}
}
impl<R: BufRead> Parser<R> {
pub fn new(reader: R) -> Self {
Self { reader }
}
pub fn parse_line(&mut self) -> Result<Option<Record>, Error> {
let mut buf = String::new();
if self.reader.read_line(&mut buf)? == 0 {
return Ok(None);
}
while buf.ends_with('\n') || buf.ends_with('\r') {
buf.pop();
}
let mut fields = FieldReader::new(&buf);
let ty = fields.parse_next::<u8>(2)?;
let record = match ty {
10 => {
let gebietsstand = parse_date(fields.next(8))?;
tracing::debug!(gebietsstand = ?gebietsstand);
let ags = fields.parse_next(2)?;
fields.skip(10);
let name = fields.next(50).trim().to_owned();
let sitz_regierung = fields.next(50).trim().to_owned();
Record::Land(Land {
gebietsstand,
ags,
name,
sitz_regierung,
})
}
20 => {
let gebietsstand = parse_date(fields.next(8))?;
tracing::debug!(gebietsstand = ?gebietsstand);
let ags = fields.parse_next(3)?;
fields.skip(9);
let name = fields.next(50).trim().to_owned();
let sitz_verwaltung = fields.next(50).trim().to_owned();
Record::Regierungsbezirk(Regierungsbezirk {
gebietsstand,
ags,
name,
sitz_verwaltung,
})
}
30 => {
let gebietsstand = parse_date(fields.next(8))?;
tracing::debug!(gebietsstand = ?gebietsstand);
let ags = fields.parse_next(3)?;
tracing::debug!(ags = ?ags);
let region = fields.parse_next(1)?;
tracing::debug!(region = ?region);
let name = fields.next(50).trim().to_owned();
tracing::debug!(name = ?name);
let sitz_verwaltung = fields.next(50).trim().to_owned();
tracing::debug!(sitz_verwaltung = ?sitz_verwaltung);
Record::Region(Region {
gebietsstand,
ags,
region,
name,
sitz_verwaltung,
})
}
40 => {
let gebietsstand = parse_date(fields.next(8))?;
tracing::debug!(gebietsstand = ?gebietsstand);
let ags = fields.parse_next(5)?;
tracing::debug!(ags = ?ags);
fields.skip(7);
let name = fields.next(50).trim().to_owned();
tracing::debug!(name = ?name);
let sitz_verwaltung = fields.next(50).trim().to_owned();
tracing::debug!(sitz_verwaltung = ?sitz_verwaltung);
Record::Kreis(Kreis {
gebietsstand,
ags,
name,
sitz_verwaltung,
})
}
50 => {
let gebietsstand = parse_date(fields.next(8))?;
tracing::debug!(gebietsstand = ?gebietsstand);
let ags = fields.parse_next(5)?;
tracing::debug!(ags = ?ags);
fields.skip(3);
let gemeindeverband = fields.parse_next(4)?;
tracing::debug!(gemeindeverband = ?gemeindeverband);
let name = fields.next(50).trim().to_owned();
tracing::debug!(name = ?name);
let sitz_verwaltung = fields.next(50).trim().to_owned();
tracing::debug!(sitz_verwaltung = ?sitz_verwaltung);
Record::Gemeindeverband(Gemeindeverband {
gebietsstand,
ags,
gemeindeverband,
name,
sitz_verwaltung,
})
}
60 => {
let gebietsstand = parse_date(fields.next(8))?;
tracing::debug!(gebietsstand = ?gebietsstand);
let ags = fields.parse_next(8)?;
tracing::debug!(ags = ?ags);
let gemeindeverband = fields.parse_next(4)?;
tracing::debug!(gemeindeverband = ?gemeindeverband);
let name = fields.next(50).trim().to_owned();
tracing::debug!(name = ?name);
fields.skip(50);
fields.skip(2);
fields.skip(4);
let area = fields.parse_next(11)?;
tracing::debug!(area = ?area);
let population_total = fields.parse_next(11)?;
tracing::debug!(population_total = ?population_total);
let population_male = fields.parse_next(11)?;
tracing::debug!(population_male = ?population_male);
fields.skip(4);
let plz = fields.next(5).to_owned();
tracing::debug!(plz = ?plz);
let plz_alt = {
let s = fields.next(5).to_owned();
if s.trim().is_empty() {
None
} else {
Some(s.to_owned())
}
};
tracing::debug!(plz_alt = ?plz_alt);
fields.skip(2);
let finanzamtbezirk = fields.next(4);
tracing::debug!(finanzamtbezirk = ?finanzamtbezirk);
fields.skip(4);
let arbeitsargenturbezirk = fields.next(5);
tracing::debug!(arbeitsargenturbezirk = ?arbeitsargenturbezirk);
let bundestagswahlkreise_von = fields.next(3);
tracing::debug!(bundestagswahlkreise_von = ?bundestagswahlkreise_von);
let bundestagswahlkreise_bis = fields.next(3);
tracing::debug!(bundestagswahlkreise_bis = ?bundestagswahlkreise_bis);
Record::Gemeinde(Gemeinde {
gebietsstand,
ags,
gemeindeverband,
name,
area,
population_total,
population_male,
plz,
})
}
ty => return Err(Error::InvalidType(ty)),
};
tracing::debug!("{:#?}", record);
Ok(Some(record))
}
}
pub fn parse_date(s: &str) -> Result<NaiveDate, ParseIntError> {
Ok(NaiveDate::from_ymd(s[0..4].parse()?, s[4..6].parse()?, s[6..8].parse()?))
}
#[derive(Clone, Debug)]
pub enum Record {
Land(Land),
Regierungsbezirk(Regierungsbezirk),
Region(Region),
Kreis(Kreis),
Gemeindeverband(Gemeindeverband),
Gemeinde(Gemeinde),
}
impl Record {
pub fn gebietsstand(&self) -> &NaiveDate {
match self {
Record::Land(land) => &land.gebietsstand,
Record::Regierungsbezirk(regierungsbezirk) => ®ierungsbezirk.gebietsstand,
Record::Region(_region) => todo!(),
Record::Kreis(kreis) => &kreis.gebietsstand,
Record::Gemeindeverband(gemeindeverband) => &gemeindeverband.gebietsstand,
Record::Gemeinde(gemeinde) => &gemeinde.gebietsstand,
}
}
pub fn ags(&self) -> &Ags {
match self {
Record::Land(land) => &land.ags,
Record::Regierungsbezirk(regierungsbezirk) => ®ierungsbezirk.ags,
Record::Region(region) => ®ion.ags,
Record::Kreis(kreis) => &kreis.ags,
Record::Gemeindeverband(gemeindeverband) => &gemeindeverband.ags,
Record::Gemeinde(gemeinde) => &gemeinde.ags,
}
}
pub fn name(&self) -> &str {
match self {
Record::Land(land) => &land.name,
Record::Regierungsbezirk(regierungsbezirk) => ®ierungsbezirk.name,
Record::Region(_region) => todo!(),
Record::Kreis(kreis) => &kreis.name,
Record::Gemeindeverband(gemeindeverband) => &gemeindeverband.name,
Record::Gemeinde(gemeinde) => &gemeinde.name,
}
}
}
#[derive(Clone, Debug)]
pub struct Land {
pub gebietsstand: NaiveDate,
pub ags: Ags,
pub name: String,
pub sitz_regierung: String,
}
#[derive(Clone, Debug)]
pub struct Regierungsbezirk {
pub gebietsstand: NaiveDate,
pub ags: Ags,
pub name: String,
pub sitz_verwaltung: String,
}
#[derive(Clone, Debug)]
pub struct Region {
pub gebietsstand: NaiveDate,
pub ags: Ags,
pub region: u8,
pub name: String,
pub sitz_verwaltung: String,
}
#[derive(Clone, Debug)]
pub struct Kreis {
pub gebietsstand: NaiveDate,
pub ags: Ags,
pub name: String,
pub sitz_verwaltung: String,
}
#[derive(Clone, Debug)]
pub struct Gemeindeverband {
pub gebietsstand: NaiveDate,
pub ags: Ags,
pub gemeindeverband: u16,
pub name: String,
pub sitz_verwaltung: String,
}
#[derive(Clone, Debug)]
pub struct Gemeinde {
pub gebietsstand: NaiveDate,
pub ags: Ags,
pub gemeindeverband: u16,
pub name: String,
pub area: u64,
pub population_total: u64,
pub population_male: u64,
pub plz: String,
}
#[derive(Clone, Debug)]
pub enum Textkennzeichen {
Markt,
KreisfreieStadt,
Stadtkreis,
Stadt,
KreisangehoerigeGemeinde,
GemeindefreiesGebietBewohnt,
GemeindefreiesGebietUnbewohnt,
GrosseKreisstadt,
}
impl FromStr for Textkennzeichen {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let c = s.parse()?;
Ok(match c {
60 => Self::Markt,
61 => Self::KreisfreieStadt,
62 => Self::Stadtkreis,
63 => Self::Stadt,
64 => Self::KreisangehoerigeGemeinde,
65 => Self::GemeindefreiesGebietBewohnt,
66 => Self::GemeindefreiesGebietUnbewohnt,
67 => Self::GrosseKreisstadt,
_ => return Err(Error::InvalidTextkennzeichen(c)),
})
}
}
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Ags {
pub land: u8,
pub regierungsbezirk: Option<u8>,
pub kreis: Option<u8>,
pub gemeinde: Option<u16>,
}
impl FromStr for Ags {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.trim();
let land = s[0..2].parse()?;
let regierungsbezirk = s.get(2..3).map(|s| s.parse()).transpose()?;
let kreis = s.get(3..5).map(|s| s.parse()).transpose()?;
let gemeinde = s.get(5..8).map(|s| s.parse()).transpose()?;
Ok(Self {
land,
regierungsbezirk,
kreis,
gemeinde,
})
}
}
impl Ags {
pub fn new_land(land: u8) -> Self {
Self::new(land, None, None, None)
}
pub fn new_regierungsbezirk(land: u8, regierungsbezirk: u8) -> Self {
Self::new(land, Some(regierungsbezirk), None, None)
}
pub fn new_kreis(land: u8, regierungsbezirk: u8, kreis: u8) -> Self {
Self::new(land, Some(regierungsbezirk), Some(kreis), None)
}
pub fn new_gemeinde(land: u8, regierungsbezirk: u8, kreis: u8, gemeinde: u16) -> Self {
Self::new(land, Some(regierungsbezirk), Some(kreis), Some(gemeinde))
}
fn new(land: u8, regierungsbezirk: Option<u8>, kreis: Option<u8>, gemeinde: Option<u16>) -> Self {
Self {
land,
regierungsbezirk,
kreis,
gemeinde,
}
}
pub fn to_regierungsbezirk(&self) -> Option<Ags> {
if let Some(regierungsbezirk) = self.regierungsbezirk {
Some(Ags::new_regierungsbezirk(self.land, regierungsbezirk))
} else {
None
}
}
pub fn to_kreis(&self) -> Option<Ags> {
if let (Some(regierungsbezirk), Some(kreis)) = (self.regierungsbezirk, self.kreis) {
Some(Ags::new_kreis(self.land, regierungsbezirk, kreis))
} else {
None
}
}
pub fn is_land(&self) -> bool {
self.regierungsbezirk.is_none()
}
pub fn is_regierungsbezirk(&self) -> bool {
self.regierungsbezirk.is_some() && self.kreis.is_none()
}
pub fn is_kreis(&self) -> bool {
self.kreis.is_some() && self.gemeinde.is_none()
}
pub fn is_gemeinde(&self) -> bool {
self.gemeinde.is_some()
}
pub fn contains(&self, other: &Self) -> bool {
if self.land != other.land {
return false;
}
match (self.regierungsbezirk, other.regierungsbezirk) {
(Some(a), Some(b)) if a != b => return false,
(Some(_), None) => return false,
_ => {}
}
match (self.kreis, other.kreis) {
(Some(a), Some(b)) if a != b => return false,
(Some(_), None) => return false,
_ => {}
}
match (self.gemeinde, other.gemeinde) {
(Some(a), Some(b)) if a != b => return false,
(Some(_), None) => return false,
_ => {}
}
true
}
}
impl Display for Ags {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{:02}", self.land)?;
if let Some(regierungsbezirk) = self.regierungsbezirk {
write!(f, "{:01}", regierungsbezirk)?;
}
if let Some(kreis) = self.kreis {
write!(f, "{:02}", kreis)?;
}
if let Some(gemeinde) = self.gemeinde {
write!(f, "{:03}", gemeinde)?;
}
Ok(())
}
}
#[derive(Clone, Debug)]
pub struct Gerichtbarkeit {
oberlandesgericht: u8,
landgericht: u8,
amtsgericht: u8,
}
pub struct Database {
laender: BTreeMap<Ags, Land>,
regierungsbezirke: BTreeMap<Ags, Regierungsbezirk>,
regionen: BTreeMap<u8, Region>,
kreise: BTreeMap<Ags, Kreis>,
gemeindeverbaende: BTreeMap<Ags, BTreeMap<u16, Gemeindeverband>>,
gemeinden: BTreeMap<Ags, Gemeinde>,
}
impl Database {
pub fn from_reader<R: BufRead>(reader: R) -> Result<Self, Error> {
Self::from_parser(Parser::new(reader))
}
pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
Self::from_parser(Parser::from_path(path)?)
}
pub fn from_parser<R: BufRead>(mut parser: Parser<R>) -> Result<Self, Error> {
let mut laender = BTreeMap::new();
let mut regierungsbezirke = BTreeMap::new();
let mut kreise = BTreeMap::new();
let mut gemeinden = BTreeMap::new();
let mut regionen = BTreeMap::new();
let mut gemeindeverbaende: BTreeMap<Ags, BTreeMap<u16, Gemeindeverband>> = BTreeMap::new();
while let Some(record) = parser.parse_line()? {
match record {
Record::Land(land) => {
laender.insert(land.ags.clone(), land);
}
Record::Regierungsbezirk(regierungsbezirk) => {
regierungsbezirke.insert(regierungsbezirk.ags.clone(), regierungsbezirk);
}
Record::Kreis(kreis) => {
kreise.insert(kreis.ags.clone(), kreis);
}
Record::Gemeinde(gemeinde) => {
gemeinden.insert(gemeinde.ags.clone(), gemeinde);
}
Record::Region(region) => {
regionen.insert(region.region, region);
}
Record::Gemeindeverband(gemeindeverband) => {
gemeindeverbaende
.entry(gemeindeverband.ags.clone())
.or_default()
.insert(gemeindeverband.gemeindeverband, gemeindeverband);
}
}
}
Ok(Self {
laender,
regierungsbezirke,
kreise,
gemeinden,
regionen,
gemeindeverbaende,
})
}
pub fn get_land(&self, ags: &Ags) -> Option<&Land> {
self.laender.get(ags)
}
pub fn get_regierungsbezirk(&self, ags: &Ags) -> Option<&Regierungsbezirk> {
self.regierungsbezirke.get(ags)
}
pub fn get_region(&self, region: u8) -> Option<&Region> {
self.regionen.get(®ion)
}
pub fn get_kreis(&self, ags: &Ags) -> Option<&Kreis> {
self.kreise.get(ags)
}
pub fn get_gemeindeverband(&self, ags: &Ags, gemeindeverband: u16) -> Option<&Gemeindeverband> {
self.gemeindeverbaende.get(ags)?.get(&gemeindeverband)
}
pub fn get_gemeinde(&self, ags: &Ags) -> Option<&Gemeinde> {
self.gemeinden.get(ags)
}
pub fn iter_laender(&self) -> impl Iterator<Item = &Land> {
self.laender.values()
}
pub fn iter_kreise_in(&self, ags: &Ags) -> impl Iterator<Item = &Kreis> {
let mut first = ags.clone();
let mut last = ags.clone();
if ags.regierungsbezirk.is_none() {
first.regierungsbezirk = Some(u8::MIN);
last.regierungsbezirk = Some(u8::MAX);
}
if ags.kreis.is_none() {
first.kreis = Some(u8::MIN);
last.kreis = Some(u8::MAX);
}
self.kreise.range(first..=last).map(|(_, kreis)| kreis)
}
pub fn iter_gemeinden_in(&self, ags: &Ags) -> impl Iterator<Item = &Gemeinde> {
let mut first = ags.clone();
let mut last = ags.clone();
if ags.regierungsbezirk.is_none() {
first.regierungsbezirk = Some(u8::MIN);
last.regierungsbezirk = Some(u8::MAX);
}
if ags.kreis.is_none() {
first.kreis = Some(u8::MIN);
last.kreis = Some(u8::MAX);
}
if ags.gemeinde.is_none() {
first.gemeinde = Some(u16::MIN);
last.gemeinde = Some(u16::MAX);
}
self.gemeinden.range(first..=last).map(|(_, gemeinde)| gemeinde)
}
}
trait Visitor {
fn begin_land(&mut self, _land: &Land) -> bool {
false
}
fn end_land(&mut self, _land: &Land) {}
fn begin_regierunsbezirk(&mut self, _regierungsbezirk: &Regierungsbezirk) -> bool {
false
}
fn end_regierungsbezirk(&mut self, _regierungsbezirk: &Regierungsbezirk) {}
fn begin_kreis(&mut self, _kreis: &Kreis) -> bool {
false
}
fn end_kreis(&mut self, _kreis: &Kreis) {}
fn begin_gemeindeverband(&mut self, _gemeindeverband: &Gemeindeverband) -> bool {
false
}
fn end_gemeindeverband(&mut self, _gemeindeverband: &Gemeindeverband) {}
fn gemeinde(&mut self, _gemeinde: &Gemeinde) {}
fn visit(&mut self, db: &Database) {
for land in db.iter_laender() {
if self.begin_land(land) {
for kreis in db.iter_kreise_in(&land.ags) {
if self.begin_kreis(kreis) {
for gemeinde in db.iter_gemeinden_in(&land.ags) {
self.gemeinde(gemeinde);
}
self.end_kreis(kreis);
}
}
self.end_land(land);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn parse_full_dataset() {
let mut parser = Parser::from_path("GV100AD_300421.txt").unwrap();
while let Some(record) = parser.parse_line().unwrap() {
println!("{:#?}", record);
}
}
#[test]
pub fn iter_gebiete() {
let db = Database::from_file("GV100AD_300421.txt").unwrap();
let kreise_saarland = db.iter_kreise_in(&Ags::new_land(10)).collect::<Vec<&Kreis>>();
assert_eq!(kreise_saarland.len(), 6);
assert_eq!(kreise_saarland[0].name, "Regionalverband Saarbrücken");
assert_eq!(kreise_saarland[1].name, "Merzig-Wadern");
assert_eq!(kreise_saarland[2].name, "Neunkirchen");
assert_eq!(kreise_saarland[3].name, "Saarlouis");
assert_eq!(kreise_saarland[4].name, "Saarpfalz-Kreis");
assert_eq!(kreise_saarland[5].name, "St. Wendel");
}
}