Skip to main content

wdl_format/config/
newline.rs

1//! Newline style within formatting configuration.
2
3use std::fmt;
4use std::str::FromStr;
5
6use schemars::JsonSchema;
7use thiserror::Error;
8
9/// Unix-style newline.
10const UNIX_NEWLINE: &str = "\n";
11
12/// Windows-style newline.
13const WINDOWS_NEWLINE: &str = "\r\n";
14
15/// The newline style to use when formatting.
16#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, JsonSchema)]
17#[schemars(rename_all = "lowercase")]
18pub enum NewlineStyle {
19    /// Use the native newline style of the platform.
20    #[default]
21    Auto,
22    /// Use Unix-style newlines (`\n`).
23    Unix,
24    /// Use Windows-style newlines (`\r\n`).
25    Windows,
26}
27
28impl fmt::Display for NewlineStyle {
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        match self {
31            Self::Auto => f.write_str("auto"),
32            Self::Unix => f.write_str("unix"),
33            Self::Windows => f.write_str("windows"),
34        }
35    }
36}
37
38/// An error returned when parsing an invalid [`NewlineStyle`] string.
39#[derive(Clone, Debug, Eq, Error, PartialEq)]
40#[error("invalid newline style `{0}`; expected one of: `auto`, `unix`, `windows`")]
41pub struct ParseNewlineStyleError(String);
42
43impl FromStr for NewlineStyle {
44    type Err = ParseNewlineStyleError;
45
46    fn from_str(s: &str) -> Result<Self, Self::Err> {
47        match s.to_ascii_lowercase().as_str() {
48            "auto" => Ok(Self::Auto),
49            "unix" => Ok(Self::Unix),
50            "windows" => Ok(Self::Windows),
51            _ => Err(ParseNewlineStyleError(s.to_string())),
52        }
53    }
54}
55
56impl NewlineStyle {
57    /// Gets the newline string for this style.
58    pub fn as_str(&self) -> &str {
59        match self {
60            NewlineStyle::Auto => {
61                if cfg!(windows) {
62                    WINDOWS_NEWLINE
63                } else {
64                    UNIX_NEWLINE
65                }
66            }
67            NewlineStyle::Unix => UNIX_NEWLINE,
68            NewlineStyle::Windows => WINDOWS_NEWLINE,
69        }
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76
77    #[test]
78    fn test_unix_newline() {
79        assert_eq!(NewlineStyle::Unix.as_str(), "\n");
80    }
81
82    #[test]
83    fn test_windows_newline() {
84        assert_eq!(NewlineStyle::Windows.as_str(), "\r\n");
85    }
86
87    #[test]
88    fn test_auto_newline() {
89        let newline = NewlineStyle::Auto.as_str();
90        assert!(newline == "\n" || newline == "\r\n");
91    }
92
93    #[test]
94    fn test_default_is_auto() {
95        assert!(matches!(NewlineStyle::default(), NewlineStyle::Auto));
96    }
97
98    #[test]
99    fn from_str_accepts_valid_values() {
100        assert_eq!("auto".parse::<NewlineStyle>().unwrap(), NewlineStyle::Auto);
101        assert_eq!("unix".parse::<NewlineStyle>().unwrap(), NewlineStyle::Unix);
102        assert_eq!(
103            "windows".parse::<NewlineStyle>().unwrap(),
104            NewlineStyle::Windows
105        );
106        assert_eq!("AUTO".parse::<NewlineStyle>().unwrap(), NewlineStyle::Auto);
107    }
108
109    #[test]
110    fn from_str_rejects_invalid_value() {
111        let err = "bad".parse::<NewlineStyle>().unwrap_err();
112        assert_eq!(
113            err.to_string(),
114            "invalid newline style `bad`; expected one of: `auto`, `unix`, `windows`"
115        );
116    }
117
118    #[test]
119    fn display_round_trips_through_from_str() {
120        for style in [
121            NewlineStyle::Auto,
122            NewlineStyle::Unix,
123            NewlineStyle::Windows,
124        ] {
125            assert_eq!(style.to_string().parse::<NewlineStyle>().unwrap(), style);
126        }
127    }
128}