use evolution_common::error::{Result, SetupError};
use std::fs::{File, OpenOptions};
use std::io::Write;
use std::path::PathBuf;
pub trait Writer<'a> {
type Buffer: 'a;
fn finish(&mut self);
fn write(&mut self, buffer: Self::Buffer);
fn try_finish(&mut self) -> Result<()>;
fn try_write(&mut self, buffer: Self::Buffer) -> Result<()>;
}
pub type WriterRef<'a, T> = dyn Writer<'a, Buffer = T>;
pub struct FixedLengthFileWriter {
inner: File,
properties: FixedLengthFileWriterProperties,
}
impl FixedLengthFileWriter {
pub fn builder() -> FixedLengthFileWriterBuilder {
FixedLengthFileWriterBuilder {
..Default::default()
}
}
pub fn properties(&self) -> &FixedLengthFileWriterProperties {
&self.properties
}
}
impl<'a> Writer<'a> for FixedLengthFileWriter {
type Buffer = &'a [u8];
fn finish(&mut self) {
self.try_finish().unwrap();
}
fn write(&mut self, buffer: &[u8]) {
self.try_write(buffer).unwrap();
}
fn try_finish(&mut self) -> Result<()> {
self.inner.flush()?;
Ok(())
}
fn try_write(&mut self, buffer: Self::Buffer) -> Result<()> {
self.inner.write_all(buffer)?;
Ok(())
}
}
pub struct FixedLengthFileWriterProperties {
force_create_new: bool,
create_or_open: bool,
truncate_existing: bool,
}
impl FixedLengthFileWriterProperties {
pub fn builder() -> FixedLengthFileWriterPropertiesBuilder {
FixedLengthFileWriterPropertiesBuilder {
..Default::default()
}
}
}
#[derive(Default)]
pub struct FixedLengthFileWriterBuilder {
out_path: Option<PathBuf>,
properties: Option<FixedLengthFileWriterProperties>,
}
impl FixedLengthFileWriterBuilder {
pub fn with_out_path(mut self, out_path: PathBuf) -> Self {
self.out_path = Some(out_path);
self
}
pub fn with_properties(mut self, properties: FixedLengthFileWriterProperties) -> Self {
self.properties = Some(properties);
self
}
pub fn try_build(self) -> Result<FixedLengthFileWriter> {
let out_path: PathBuf = self.out_path.ok_or_else(|| {
Box::new(SetupError::new(
"Required field 'out_path' was not provided, exiting...",
))
})?;
let properties: FixedLengthFileWriterProperties = self.properties.ok_or_else(|| {
Box::new(SetupError::new(
"Required field 'properties' was not provided, exiting...",
))
})?;
let inner: File = OpenOptions::new()
.write(true)
.create_new(properties.force_create_new)
.create(properties.create_or_open)
.append(properties.create_or_open && !properties.truncate_existing)
.truncate(properties.truncate_existing && !properties.force_create_new)
.open(out_path)?;
Ok(FixedLengthFileWriter { inner, properties })
}
pub fn build(self) -> FixedLengthFileWriter {
self.try_build().unwrap()
}
}
#[derive(Default)]
pub struct FixedLengthFileWriterPropertiesBuilder {
force_create_new: Option<bool>,
create_or_open: Option<bool>,
truncate_existing: Option<bool>,
}
impl FixedLengthFileWriterPropertiesBuilder {
pub fn with_force_create_new(mut self, force_create_new: bool) -> Self {
self.force_create_new = Some(force_create_new);
self
}
pub fn with_create_or_open(mut self, create_or_open: bool) -> Self {
self.create_or_open = Some(create_or_open);
self
}
pub fn with_truncate_existing(mut self, truncate_existing: bool) -> Self {
self.truncate_existing = Some(truncate_existing);
self
}
pub fn try_build(self) -> Result<FixedLengthFileWriterProperties> {
let force_create_new: bool = self.force_create_new.ok_or_else(|| {
Box::new(SetupError::new(
"Required field 'force_create_new' was not provided, exiting...",
))
})?;
let create_or_open: bool = self.create_or_open.ok_or_else(|| {
Box::new(SetupError::new(
"Required field 'create_or_open' was not provided, exiting...",
))
})?;
let truncate_existing: bool = self.truncate_existing.ok_or_else(|| {
Box::new(SetupError::new(
"Required field 'truncate_existing' was not provided, exiting...",
))
})?;
Ok(FixedLengthFileWriterProperties {
force_create_new,
create_or_open,
truncate_existing,
})
}
pub fn build(self) -> FixedLengthFileWriterProperties {
self.try_build().unwrap()
}
}