1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use std::io::prelude::*;
use std::marker::PhantomData;
use std::mem::drop;

use anyhow::Result;
use csv;
use serde::Serialize;

mod chunks;
mod thread;
mod transform;

pub use chunks::{ChunkWriter, UnchunkWriter};
pub use thread::ThreadObjectWriter;
pub use transform::MapWriter;

/// Trait for writing objects to some kind of sink.
pub trait ObjectWriter<T>: Sized {
    /// Write one object.
    fn write_object(&mut self, object: T) -> Result<()>;

    /// Write an iterator full of objects.
    fn write_all_objects<I>(&mut self, objects: I) -> Result<usize>
    where
        I: Iterator<Item = T>,
    {
        let mut count = 0;
        for obj in objects {
            self.write_object(obj)?;
            count += 1;
        }
        Ok(count)
    }

    /// Write an iterator of objects and finish the writer.
    fn write_and_finish<I>(mut self, objects: I) -> Result<usize>
    where
        I: Iterator<Item = T>,
    {
        let n = self.write_all_objects(objects)?;
        self.finish()?;
        Ok(n)
    }

    /// Finish and close the target.
    fn finish(self) -> Result<usize>;

    /// Wrap this object writer in a transformed writer.
    fn with_transform<F, T2>(self, transform: F) -> MapWriter<F, T2, T, Self>
    where
        F: Fn(T2) -> Result<T>,
    {
        MapWriter {
            _phantom: PhantomData,
            transform,
            writer: self,
        }
    }
}

/// References can be used as object writers; however, [ObjectWriter::finish] must
/// be called on the owned writer, not a reference.  Closing the reference is a
/// no-op.
impl<T, W> ObjectWriter<T> for &mut W
where
    W: ObjectWriter<T>,
{
    fn write_object(&mut self, object: T) -> Result<()> {
        (**self).write_object(object)
    }

    fn finish(self) -> Result<usize> {
        // closing a reference does *not* close the write
        Ok(0)
    }
}

impl<T: Serialize, W: Write> ObjectWriter<T> for csv::Writer<W> {
    fn write_object(&mut self, object: T) -> Result<()> {
        self.serialize(object)?;
        Ok(())
    }

    fn finish(mut self) -> Result<usize> {
        self.flush()?;
        drop(self);
        Ok(0)
    }
}