1use std::{
4 env,
5 fs::File,
6 io::{self, IsTerminal as _},
7 path::{Path, PathBuf},
8};
9
10pub mod genotype;
11pub use genotype::Genotype;
12
13pub mod sample;
14pub use sample::Sample;
15
16pub mod site;
17pub use site::Site;
18
19#[derive(Debug)]
21pub enum ReadStatus<T> {
22 Read(T),
24 Error(io::Error),
26 Done,
28}
29
30impl<T> ReadStatus<T> {
31 fn map<U, F>(self, op: F) -> ReadStatus<U>
32 where
33 F: FnOnce(T) -> U,
34 {
35 match self {
36 ReadStatus::Read(t) => ReadStatus::Read(op(t)),
37 ReadStatus::Error(e) => ReadStatus::Error(e),
38 ReadStatus::Done => ReadStatus::Done,
39 }
40 }
41}
42
43#[derive(Debug)]
45pub enum Input {
46 Path(PathBuf),
48 Stdin,
50}
51
52impl Input {
53 pub const ENV_KEY_DISABLE_CHECK: &'static str = "SFS_ALLOW_STDIN";
59
60 pub fn new(input: Option<PathBuf>) -> io::Result<Self> {
62 let check = env::var(Self::ENV_KEY_DISABLE_CHECK).is_err();
63
64 if input.is_some() && !io::stdin().is_terminal() && check {
65 Err(io::Error::new(
66 io::ErrorKind::Other,
67 "received input both via file and stdin",
68 ))
69 } else if input.is_none() && std::io::stdin().is_terminal() && check {
70 Err(io::Error::new(
71 io::ErrorKind::Other,
72 "received no input via file or stdin",
73 ))
74 } else {
75 Ok(Self::new_unchecked(input))
76 }
77 }
78
79 pub fn new_unchecked(input: Option<PathBuf>) -> Self {
81 if let Some(path) = input {
82 Self::Path(path)
83 } else {
84 Self::Stdin
85 }
86 }
87
88 pub fn open(&self) -> io::Result<Reader> {
90 match self {
91 Input::Path(path) => File::open(path).map(io::BufReader::new).map(Reader::File),
92 Input::Stdin => Ok(Reader::Stdin(io::stdin().lock())),
93 }
94 }
95
96 pub fn as_path(&self) -> Option<&Path> {
98 match self {
99 Input::Path(path) => Some(path.as_ref()),
100 Input::Stdin => None,
101 }
102 }
103}
104
105impl From<Input> for Option<PathBuf> {
106 fn from(input: Input) -> Self {
107 match input {
108 Input::Path(path) => Some(path),
109 Input::Stdin => None,
110 }
111 }
112}
113
114#[derive(Debug)]
116pub enum Reader {
117 File(io::BufReader<File>),
119 Stdin(io::StdinLock<'static>),
121}