]> git.lizzy.rs Git - rust.git/commitdiff
Add methods to serialize Config to TOML.
authorMichael Killough <michaeljkillough@gmail.com>
Tue, 16 May 2017 11:08:24 +0000 (18:08 +0700)
committerMichael Killough <michaeljkillough@gmail.com>
Tue, 16 May 2017 11:08:24 +0000 (18:08 +0700)
Two different modes:

 - Serialize the full Config object. This is useful as
   `Config::default().to_toml()` to output a rustfmt.toml with defaults
   (#317).
 - Serialize only the options that have been accessed. This could be
   useful to output a minimal rustfmt.toml for a project. (If the
   default value of any unused config item changes, you'll then get the
   new default when you come to use it).

This commit doesn't expose this anywhere - deciding a sensible CLI is a
bit trickier.

This commit also has very simple error reporting (Result<String,
String>) - once the CLI is decided, a more sensible method of reporting
errors might become obvious.

src/config.rs
src/file_lines.rs
src/lists.rs
src/utils.rs

index 44c40f2ac6cb4828b80b70ddf0fc6ba7584cc5d0..e33c35f1054eab3e5414899b162c2e49816a663f 100644 (file)
@@ -25,7 +25,7 @@ pub enum $e {
             $( $x ),+
         }
 
-        impl_enum_decodable!($e, $( $x ),+);
+        impl_enum_serialize_and_deserialize!($e, $( $x ),+);
     }
 }
 
@@ -247,10 +247,10 @@ pub struct Config {
         // Just like the Config struct but with each property wrapped
         // as Option<T>. This is used to parse a rustfmt.toml that doesn't
         // specity all properties of `Config`.
-        // We first parse into `ParsedConfig`, then create a default `Config`
-        // and overwrite the properties with corresponding values from `ParsedConfig`
-        #[derive(Deserialize, Clone)]
-        pub struct ParsedConfig {
+        // We first parse into `PartialConfig`, then create a default `Config`
+        // and overwrite the properties with corresponding values from `PartialConfig`.
+        #[derive(Deserialize, Serialize, Clone)]
+        struct PartialConfig {
             $(pub $i: Option<$ty>),+
         }
 
@@ -263,7 +263,7 @@ pub fn $i(&self) -> $ty {
             }
             )+
 
-            fn fill_from_parsed_config(mut self, parsed: ParsedConfig) -> Config {
+            fn fill_from_parsed_config(mut self, parsed: PartialConfig) -> Config {
             $(
                 if let Some(val) = parsed.$i {
                     self.$i = val;
@@ -306,6 +306,38 @@ pub fn from_toml(toml: &str) -> Result<Config, String> {
                 }
             }
 
+            pub fn used_to_toml(&self) -> Result<String, String> {
+                let mut partial = PartialConfig {
+                    $(
+                        $i: if self.tracker.was_accessed(stringify!($i)) {
+                                Some(self.$i.clone())
+                            } else {
+                                None
+                            },
+                    )+
+                };
+
+                // file_lines is special and can't be specified in toml.
+                partial.file_lines = None;
+
+                toml::to_string(&partial)
+                    .map_err(|e| format!("Could not output config: {}", e.to_string()))
+            }
+
+            pub fn to_toml(&self) -> Result<String, String> {
+                let mut partial = PartialConfig {
+                    $(
+                        $i: Some(self.$i.clone()),
+                    )+
+                };
+
+                // file_lines is special and can't be specified in toml.
+                partial.file_lines = None;
+
+                toml::to_string(&partial)
+                    .map_err(|e| format!("Could not output config: {}", e.to_string()))
+            }
+
             pub fn override_value(&mut self, key: &str, val: &str)
                 -> result::Result<(), Box<error::Error + Send + Sync>>
             {
index a31fe72511ce1271ae4715614134f8d5e37d5a52..c6c4cc3e597e92f85dfe70707b13a37dcf5b678c 100644 (file)
@@ -216,6 +216,16 @@ fn deserialize<D>(_: D) -> Result<Self, D::Error>
     }
 }
 
+// We also want to avoid attempting to serialize a FileLines to toml. The
+// `Config` struct should ensure this impl is never reached.
+impl ::serde::ser::Serialize for FileLines {
+    fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error>
+        where S: ::serde::ser::Serializer
+    {
+        panic!("FileLines cannot be serialized. This is a rustfmt bug.");
+    }
+}
+
 #[cfg(test)]
 mod test {
     use super::Range;
index 5e03afff6fdf67d0fa4fbc6fd67b2f5dc9be43d1..613f31412e0d63747fd654c83a7e5cac84c89cae 100644 (file)
@@ -35,7 +35,7 @@ pub enum ListTactic {
     Mixed,
 }
 
-impl_enum_decodable!(ListTactic, Vertical, Horizontal, HorizontalVertical, Mixed);
+impl_enum_serialize_and_deserialize!(ListTactic, Vertical, Horizontal, HorizontalVertical, Mixed);
 
 #[derive(Eq, PartialEq, Debug, Copy, Clone)]
 pub enum SeparatorTactic {
@@ -44,7 +44,7 @@ pub enum SeparatorTactic {
     Vertical,
 }
 
-impl_enum_decodable!(SeparatorTactic, Always, Never, Vertical);
+impl_enum_serialize_and_deserialize!(SeparatorTactic, Always, Never, Vertical);
 
 impl SeparatorTactic {
     pub fn from_bool(b: bool) -> SeparatorTactic {
index 059040c70a237b62ac5b8d655e705a45beb1d070..bb9d178b83fcb2d998fd5fedbe02c4acabdd9e32 100644 (file)
@@ -189,10 +189,29 @@ pub fn trim_newlines(input: &str) -> &str {
     }
 }
 
-// Macro for deriving implementations of Decodable for enums
+// Macro for deriving implementations of Serialize/Deserialize for enums
 #[macro_export]
-macro_rules! impl_enum_decodable {
+macro_rules! impl_enum_serialize_and_deserialize {
     ( $e:ident, $( $x:ident ),* ) => {
+        impl ::serde::ser::Serialize for $e {
+            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+                where S: ::serde::ser::Serializer
+            {
+                use serde::ser::Error;
+
+                // We don't know whether the user of the macro has given us all options.
+                #[allow(unreachable_patterns)]
+                match *self {
+                    $(
+                        $e::$x => serializer.serialize_str(stringify!($x)),
+                    )*
+                    _ => {
+                        Err(S::Error::custom(format!("Cannot serialize {:?}", self)))
+                    }
+                }
+            }
+        }
+
         impl<'de> ::serde::de::Deserialize<'de> for $e {
             fn deserialize<D>(d: D) -> Result<Self, D::Error>
                     where D: ::serde::Deserializer<'de> {