Repository: toml-rs/toml (language: rust)

Issue:
Parsed `Key` misbehaves, can panic
When using `string.parse::<toml_edit::Key>()`, the value of the key *changes* when inserted into a document.

For example, the following snippet fails, because a key of `bbb` should have been inserted into the doc, but instead `aaa` is inserted into the doc. (Presumably this has to do with the fact that the key is represented as a `RawStringInner::Spanned`.)

```rust
use toml_edit::{Document, Key, Item, Value, Formatted};

fn main() {
    let mut doc = r#"aaaaaa = 1"#.parse::<Document>().unwrap();
    let key = "bbb".parse::<Key>().unwrap();
    let mut table = doc.as_table_mut();
    table.insert_formatted(&key, Item::Value(Value::Integer(Formatted::new(2))));
    
    assert_eq!(doc.to_string(), "aaaaaa = 1\nbbb = 2\n");
}
```

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=24543f24fd94c8622e88929df3f1c1f0

If the original document is shorter than the length of the key, this will panic.

```rust
use toml_edit::{Document, Key, Item, Value, Formatted};

fn main() {
    let mut doc = r#"a=1"#.parse::<Document>().unwrap();
    let key = "bbbbbb".parse::<Key>().unwrap();
    let mut table = doc.as_table_mut();
    table.insert_formatted(&key, Item::Value(Value::Integer(Formatted::new(2))));
    
    assert_eq!(doc.to_string(), "a=1\nbbbbbb = 2\n");
}
```

    thread 'main' panicked at 'span 0..6 should be in input:
    ```
    a=1
    ```'

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=f2b0eaaa343155ef54002a7242013184

This seems to have started in version 0.18


Discussion / hints:
Note that we discovered this because we use the following function to create keys that are always surrounded with double quotes, because that matches the format of the toml documents we're editing.

```rust
fn create_key_with_quotes(str: &str) -> Key {
    // The _only_ way to affect the key's `.repr` (internal representation, whether it has quotes or
    // not) is to set it while it's parsed. Once it's created, we can't change it, and creating it
    // via a method will use a default repr.
    //
    // So, we're going to *parse* a string with quotes already around it.
    //
    // We could just take the str given, slap some quotes around it, and call it good. Which would
    // work unless the str has a quote in it! So we need to use toml_edit to *build* the key, and
    // then use toml_edit to parse the key.
    //
    // toml_edit::Formatted<String> should always have double quotes around it (I think...) so we
    // can use that to build the repr, then parse it.

    let string = str.to_string();
    let formatted_string: Formatted<String> = Formatted::new(string);
    let repr = formatted_string.to_string();
    repr.parse().unwrap()
}
```

Fix patch:
diff --git a/crates/toml_edit/src/key.rs b/crates/toml_edit/src/key.rs
index 203445a7..b7038c36 100644
--- a/crates/toml_edit/src/key.rs
+++ b/crates/toml_edit/src/key.rs
@@ -128,11 +128,17 @@ impl Key {
     }
 
     fn try_parse_simple(s: &str) -> Result<Key, crate::TomlError> {
-        parser::parse_key(s)
+        let mut key = parser::parse_key(s)?;
+        key.despan(s);
+        Ok(key)
     }
 
     fn try_parse_path(s: &str) -> Result<Vec<Key>, crate::TomlError> {
-        parser::parse_key_path(s)
+        let mut keys = parser::parse_key_path(s)?;
+        for key in &mut keys {
+            key.despan(s);
+        }
+        Ok(keys)
     }
 }
 


Test patch:
diff --git a/crates/toml_edit/tests/testsuite/parse.rs b/crates/toml_edit/tests/testsuite/parse.rs
index 9f59f69d..f1c3c27c 100644
--- a/crates/toml_edit/tests/testsuite/parse.rs
+++ b/crates/toml_edit/tests/testsuite/parse.rs
@@ -1475,3 +1475,16 @@ p.a=4
     let actual = document.to_string();
     assert_eq(input, actual);
 }
+
+#[test]
+fn despan_keys() {
+    let mut doc = r#"aaaaaa = 1"#.parse::<Document>().unwrap();
+    let key = "bbb".parse::<Key>().unwrap();
+    let table = doc.as_table_mut();
+    table.insert_formatted(
+        &key,
+        toml_edit::Item::Value(Value::Integer(toml_edit::Formatted::new(2))),
+    );
+
+    assert_eq!(doc.to_string(), "aaaaaa = 1\nbbb = 2\n");
+}