1use crate::Error::InvalidFileExtension;
2use crate::gml::write_impl::serialize;
3use crate::{CitygmlFormat, Error};
4use ecitygml_core::model::core::CityModel;
5use egml::io::util::Formatting;
6use std::fs::{File, OpenOptions};
7use std::io::{BufWriter, Write};
8use std::path::Path;
9
10#[derive(Debug, Clone)]
13pub struct GmlWriter<W: Write> {
14 writer: W,
15 format: CitygmlFormat,
16 formatting: Formatting,
17}
18
19impl<W: Write> GmlWriter<W> {
20 pub fn new(writer: W, format: CitygmlFormat) -> Self {
21 Self {
22 writer,
23 format,
24 formatting: Formatting::default(),
25 }
26 }
27
28 pub fn with_formatting(mut self, formatting: Formatting) -> Self {
29 self.formatting = formatting;
30 self
31 }
32
33 pub fn finish(self, city_model: CityModel) -> Result<(), Error> {
34 match self.format {
35 CitygmlFormat::Gml => {
36 let mut w = BufWriter::new(self.writer);
37 serialize(&mut w, city_model, self.formatting)?;
38 }
39 CitygmlFormat::GmlZst => {
40 let mut encoder = zstd::Encoder::new(BufWriter::new(self.writer), 9)?;
41 serialize(&mut encoder, city_model, self.formatting)?;
42 encoder.finish()?;
43 }
44 CitygmlFormat::GmlGz => {
45 let mut encoder = flate2::write::GzEncoder::new(
46 BufWriter::new(self.writer),
47 flate2::Compression::default(),
48 );
49 serialize(&mut encoder, city_model, self.formatting)?;
50 encoder.finish()?;
51 }
52 }
53
54 Ok(())
55 }
56}
57
58impl GmlWriter<File> {
59 pub fn from_path(path: impl AsRef<Path>) -> Result<Self, Error> {
60 let format = CitygmlFormat::from_path(path.as_ref()).ok_or_else(|| {
61 InvalidFileExtension(
62 path.as_ref()
63 .extension()
64 .and_then(|ext| ext.to_str())
65 .unwrap_or_default()
66 .to_string(),
67 )
68 })?;
69
70 let file = OpenOptions::new()
71 .create(true)
72 .write(true)
73 .truncate(true)
74 .open(path)?;
75 Ok(Self::new(file, format))
76 }
77
78 pub fn from_base_path_with_format(
79 base_path: impl AsRef<Path>,
80 format: CitygmlFormat,
81 ) -> Result<Self, Error> {
82 let mut path = base_path.as_ref().as_os_str().to_os_string();
83 path.push(".");
84 path.push(format.extension());
85
86 let file = OpenOptions::new()
87 .create(true)
88 .write(true)
89 .truncate(true)
90 .open(path)?;
91 Ok(Self::new(file, format))
92 }
93}