1use crate::{Encoding, PathExt, Result};
2use std::fmt;
3use std::path::{Path, PathBuf};
4use std::str::FromStr;
5
6#[derive(Debug, Clone, PartialEq)]
8pub enum Sink {
9 Stdout,
11 Path(PathBuf),
13}
14
15impl Sink {
16 pub fn encoding(&self) -> Option<Encoding> {
19 match self {
20 Self::Stdout => None,
21 Self::Path(path) => Encoding::from_path(path),
22 }
23 }
24}
25
26impl From<&str> for Sink {
27 fn from(s: &str) -> Self {
28 if s == "-" {
29 Self::Stdout
30 } else {
31 Self::Path(PathBuf::from(s))
32 }
33 }
34}
35
36impl From<&Path> for Sink {
37 fn from(path: &Path) -> Self {
38 Self::Path(path.to_path_buf())
39 }
40}
41
42impl FromStr for Sink {
43 type Err = std::convert::Infallible;
44
45 fn from_str(s: &str) -> Result<Self, Self::Err> {
46 Ok(From::from(s))
47 }
48}
49
50impl fmt::Display for Sink {
51 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52 match self {
53 Self::Stdout => write!(f, "<stdout>"),
54 Self::Path(path) => path
55 .relative_to_cwd()
56 .unwrap_or_else(|| path.clone())
57 .display()
58 .fmt(f),
59 }
60 }
61}
62
63#[cfg(test)]
64mod test {
65 use super::*;
66 use pretty_assertions::assert_eq;
67
68 #[test]
69 fn test_from_str() {
70 assert_eq!(Sink::from_str("-"), Ok(Sink::Stdout));
71 assert_eq!(
72 Sink::from_str("foo.json"),
73 Ok(Sink::Path(PathBuf::from("foo.json")))
74 );
75 }
76
77 #[test]
78 fn test_encoding() {
79 assert_eq!(Sink::from("-").encoding(), None);
80 assert_eq!(Sink::from("foo").encoding(), None);
81 assert_eq!(Sink::from("foo.json").encoding(), Some(Encoding::Json));
82 }
83
84 #[test]
85 fn test_to_string() {
86 assert_eq!(&Sink::Stdout.to_string(), "<stdout>");
87 assert_eq!(&Sink::from("Cargo.toml").to_string(), "Cargo.toml");
88 assert_eq!(
89 &Sink::from(std::fs::canonicalize("src/lib.rs").unwrap().as_path()).to_string(),
90 "src/lib.rs"
91 );
92 assert_eq!(
93 &Sink::from("/non-existent/path").to_string(),
94 "/non-existent/path"
95 );
96 }
97}