Repository: toml-rs/toml (rust)

Issue:
Decor in `DocumentMut` is ignored
## Example

```rs
use toml_edit::*;

let mut document = DocumentMut::new();
document.decor_mut().set_prefix("# HEADER\n");
document.decor_mut().set_prefix("# FOOTER\n");
println!("{document}");

document.as_table_mut().insert("key", value("value"));
println!("{document}");
```

## Expected

```
# HEADER
# FOOTER
# HEADER
key = "value"
# FOOTER
```

## Actual

```
key = "value"
```

Pull request description:
Decor in DocumentMut no longer ignored
fixes #727 

When serializing the DocumentMut, the set Decor is now included. Decor suffix is written BEFORE trailing. Nothing changed about decoding so prefix at top of file will still belong to the first item and suffix at bottom will still belong to the last item. 

Patch:
diff --git a/crates/toml_edit/src/encode.rs b/crates/toml_edit/src/encode.rs
index a8ccaa2a..b6142a6c 100644
--- a/crates/toml_edit/src/encode.rs
+++ b/crates/toml_edit/src/encode.rs
@@ -6,7 +6,9 @@ use toml_datetime::Datetime;
 use crate::inline_table::DEFAULT_INLINE_KEY_DECOR;
 use crate::key::Key;
 use crate::repr::{Formatted, Repr, ValueRepr};
-use crate::table::{DEFAULT_KEY_DECOR, DEFAULT_KEY_PATH_DECOR, DEFAULT_TABLE_DECOR};
+use crate::table::{
+    DEFAULT_KEY_DECOR, DEFAULT_KEY_PATH_DECOR, DEFAULT_ROOT_DECOR, DEFAULT_TABLE_DECOR,
+};
 use crate::value::{
     DEFAULT_LEADING_VALUE_DECOR, DEFAULT_TRAILING_VALUE_DECOR, DEFAULT_VALUE_DECOR,
 };
@@ -197,6 +199,9 @@ pub(crate) fn encode_value(
 
 impl Display for DocumentMut {
     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+        let decor = self.decor();
+        decor.prefix_encode(f, None, DEFAULT_ROOT_DECOR.0)?;
+
         let mut path = Vec::new();
         let mut last_position = 0;
         let mut tables = Vec::new();
@@ -214,6 +219,7 @@ impl Display for DocumentMut {
         for (_, table, path, is_array) in tables {
             visit_table(f, None, table, &path, is_array, &mut first_table)?;
         }
+        decor.suffix_encode(f, None, DEFAULT_ROOT_DECOR.1)?;
         self.trailing().encode_with_default(f, None, "")
     }
 }
diff --git a/crates/toml_edit/src/table.rs b/crates/toml_edit/src/table.rs
index 2b52aec7..2863946f 100644
--- a/crates/toml_edit/src/table.rs
+++ b/crates/toml_edit/src/table.rs
@@ -504,6 +504,7 @@ fn decorate_table(table: &mut Table) {
 }
 
 // `key1 = value1`
+pub(crate) const DEFAULT_ROOT_DECOR: (&str, &str) = ("", "");
 pub(crate) const DEFAULT_KEY_DECOR: (&str, &str) = ("", " ");
 pub(crate) const DEFAULT_TABLE_DECOR: (&str, &str) = ("\n", "");
 pub(crate) const DEFAULT_KEY_PATH_DECOR: (&str, &str) = ("", "");


Test patch:
diff --git a/crates/toml_edit/tests/testsuite/edit.rs b/crates/toml_edit/tests/testsuite/edit.rs
index 3b6a21a2..01d9ef02 100644
--- a/crates/toml_edit/tests/testsuite/edit.rs
+++ b/crates/toml_edit/tests/testsuite/edit.rs
@@ -41,6 +41,15 @@ impl Test {
         }
         self
     }
+    fn running_on_doc<F>(&mut self, func: F) -> &mut Self
+    where
+        F: Fn(&mut DocumentMut),
+    {
+        {
+            func(&mut self.doc);
+        }
+        self
+    }
 
     #[track_caller]
     fn produces_display(&self, expected: snapbox::data::Inline) -> &Self {
@@ -49,6 +58,97 @@ impl Test {
     }
 }
 
+#[test]
+fn test_add_root_decor() {
+    given(
+        r#"[package]
+name = "hello"
+version = "1.0.0"
+
+[[bin]]
+name = "world"
+path = "src/bin/world/main.rs"
+
+[dependencies]
+nom = "4.0" # future is here
+
+[[bin]]
+name = "delete me please"
+path = "src/bin/dmp/main.rs""#,
+    )
+    .running_on_doc(|document| {
+        document.decor_mut().set_prefix("# Some Header\n\n");
+        document.decor_mut().set_suffix("# Some Footer");
+        document.set_trailing("\n\ntrailing...");
+    })
+    .produces_display(str![[r#"
+# Some Header
+
+[package]
+name = "hello"
+version = "1.0.0"
+
+[[bin]]
+name = "world"
+path = "src/bin/world/main.rs"
+
+[dependencies]
+nom = "4.0" # future is here
+
+[[bin]]
+name = "delete me please"
+path = "src/bin/dmp/main.rs"
+# Some Footer
+
+trailing...
+"#]]);
+}
+
+/// Tests that default decor is None for both suffix and prefix and that this means empty strings
+#[test]
+fn test_no_root_decor() {
+    given(
+        r#"[package]
+name = "hello"
+version = "1.0.0"
+
+[[bin]]
+name = "world"
+path = "src/bin/world/main.rs"
+
+[dependencies]
+nom = "4.0" # future is here
+
+[[bin]]
+name = "delete me please"
+path = "src/bin/dmp/main.rs""#,
+    )
+    .running_on_doc(|document| {
+        assert!(document.decor().prefix().is_none());
+        assert!(document.decor().suffix().is_none());
+        document.set_trailing("\n\ntrailing...");
+    })
+    .produces_display(str![[r#"
+[package]
+name = "hello"
+version = "1.0.0"
+
+[[bin]]
+name = "world"
+path = "src/bin/world/main.rs"
+
+[dependencies]
+nom = "4.0" # future is here
+
+[[bin]]
+name = "delete me please"
+path = "src/bin/dmp/main.rs"
+
+
+trailing...
+"#]]);
+}
+
 // insertion
 
 #[test]