bstree_file_readonly/cliargs/
csvargs.rs

1//! Generic arguments used to read CSV data from a file or from stdin.
2
3use csv::{Reader, ReaderBuilder};
4use std::fs::File;
5use std::io::{stdin, Error, Read};
6use std::path::PathBuf;
7use structopt::StructOpt;
8
9#[derive(Debug, StructOpt)]
10pub struct CsvArgs {
11  #[structopt(long, default_value = "8096")]
12  /// Input buffer capacity in bytes
13  capacity: usize,
14  #[structopt(name = "separator", short = "s", long, default_value = ",")]
15  /// ASCII input file delimiter
16  delimiter: char,
17  #[structopt(short = "q", long)]
18  /// Support fields double quote parsing
19  use_double_quote: bool,
20  #[structopt(short = "e", long)]
21  /// Use the \ escape character
22  use_escape: bool,
23  #[structopt(short = "x", long)]
24  /// Do not generate an Error but a Warning if the number of columns is variable
25  flexible: bool,
26  #[structopt(short = "h", long)]
27  /// The input file contains a header line (the first non-commented line)
28  header: bool,
29  #[structopt(short = "c", long)]
30  /// The input file contains comments (lines starting by #)
31  comments: bool,
32  #[structopt(long, parse(from_os_str))]
33  /// Input file (stdin if not present)
34  input: Option<PathBuf>,
35}
36
37impl CsvArgs {
38  fn create_reader_builder(&self) -> ReaderBuilder {
39    let mut reader_builder = csv::ReaderBuilder::new();
40    reader_builder.delimiter(self.delimiter as u8);
41    reader_builder.has_headers(self.header);
42    reader_builder.double_quote(self.use_double_quote);
43    reader_builder.flexible(self.flexible);
44    reader_builder.buffer_capacity(self.capacity);
45    if self.use_escape {
46      reader_builder.escape(Some(b'\\'));
47    }
48    if self.comments {
49      reader_builder.comment(Some(b'#'));
50    }
51    reader_builder
52  }
53
54  /// Configure the reader, get it, and call the given function providing the created reader.
55  /// ## Note
56  /// * we use this strategy to use monomorphization instead of returning a trait object of type
57  ///   `Reader<Box<dyn Read>>`
58  pub fn call_once<F>(self, func: F) -> Result<F::Output, Error>
59  where
60    F: FnUsingReader,
61  {
62    // Configure the reader (before creating it)
63    let reader_builder = self.create_reader_builder();
64    // Create a reader from file or stdin
65    match self.input {
66      Some(ref path_buf) => {
67        let reader = reader_builder.from_reader(File::open(path_buf)?);
68        func.call(reader)
69      }
70      None => {
71        let reader = reader_builder.from_reader(stdin());
72        func.call(reader)
73      }
74    }
75  }
76}
77
78/// Defines a function which depends on a specific `Read` instance.
79pub trait FnUsingReader {
80  type Output;
81
82  fn call<R: Read>(self, reader: Reader<R>) -> Result<Self::Output, Error>;
83}