Repository: toml-rs/toml (rust)

Issue:
`toml` outputs negative numbers for large u64 values
For large u64 values, `tom::to_string` generates negative u64 numbers.

Code:
```rust
use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize)]
pub struct Config {
    pub seed: u64,
}

fn main() {

    let cfg = Config {
        seed: 16237911273155533842,
    };
    println!("{}", toml::to_string(&cfg).unwrap());
}
```

Running it:
```bash
~/code/github/repro/repro-2 ❯ cargo run --release
   Compiling repro-2 v0.1.0 (/Users/maxime/Code/github/repro/repro-2)
    Finished release [optimized] target(s) in 0.78s
     Running `target/release/repro-2`
seed = -2208832800554017774

~/code/github/repro/repro-2 ❯ cargo run
   Compiling repro-2 v0.1.0 (/Users/maxime/Code/github/repro/repro-2)
    Finished dev [unoptimized + debuginfo] target(s) in 0.29s
     Running `target/debug/repro-2`
seed = -2208832800554017774
```


Rust version:
```bash
~/code/github/repro/repro-2 ❯ rustc --version
rustc 1.67.0 (fc594f156 2023-01-24)
~/code/github/repro/repro-2 ❯ cargo version
cargo 1.67.0 (8ecd4f20a 2023-01-10)
```


Crate versions:
```bash
~/code/github/repro/repro-2 ❯ cargo tree
repro-2 v0.1.0 (/Users/maxime/Code/github/repro/repro-2)
├── serde v1.0.152
│   └── serde_derive v1.0.152 (proc-macro)
│       ├── proc-macro2 v1.0.51
│       │   └── unicode-ident v1.0.6
│       ├── quote v1.0.23
│       │   └── proc-macro2 v1.0.51 (*)
│       └── syn v1.0.107
│           ├── proc-macro2 v1.0.51 (*)
│           ├── quote v1.0.23 (*)
│           └── unicode-ident v1.0.6
└── toml v0.7.1
    ├── serde v1.0.152 (*)
    ├── serde_spanned v0.6.1
    │   └── serde v1.0.152 (*)
    ├── toml_datetime v0.6.1
    │   └── serde v1.0.152 (*)
    └── toml_edit v0.19.2
        ├── indexmap v1.9.2
        │   └── hashbrown v0.12.3
        │   [build-dependencies]
        │   └── autocfg v1.1.0
        ├── nom8 v0.2.0
        │   └── memchr v2.5.0
        ├── serde v1.0.152 (*)
        ├── serde_spanned v0.6.1 (*)
        └── toml_datetime v0.6.1 (*)
```

Setup:
```
OS: macOS 13.2 22D49 arm64
Host: MacBookPro18,1
CPU: Apple M1 Pro
```


I am not able to reproduce this bug in the Rust Playground.

Pull request:
fix(ser): Error on too-large u64 
This is better than going negative

Fixes #511

Patch:
diff --git a/crates/toml_edit/src/ser/mod.rs b/crates/toml_edit/src/ser/mod.rs
index 9d639013..2c310206 100644
--- a/crates/toml_edit/src/ser/mod.rs
+++ b/crates/toml_edit/src/ser/mod.rs
@@ -20,6 +20,8 @@ use crate::visit_mut::VisitMut;
 pub enum Error {
     /// Type could not be serialized to TOML
     UnsupportedType(Option<&'static str>),
+    /// Value was out of range for the given type
+    OutOfRange(Option<&'static str>),
     /// `None` could not be serialized to TOML
     UnsupportedNone,
     /// Key was not convertable to `String` for serializing to TOML
@@ -53,6 +55,8 @@ impl std::fmt::Display for Error {
         match self {
             Self::UnsupportedType(Some(t)) => write!(formatter, "unsupported {t} type"),
             Self::UnsupportedType(None) => write!(formatter, "unsupported rust type"),
+            Self::OutOfRange(Some(t)) => write!(formatter, "out-of-range value for {t} type"),
+            Self::OutOfRange(None) => write!(formatter, "out-of-range value"),
             Self::UnsupportedNone => "unsupported None value".fmt(formatter),
             Self::KeyNotString => "map key was not a string".fmt(formatter),
             Self::DateInvalid => "a serialized date was invalid".fmt(formatter),
diff --git a/crates/toml_edit/src/ser/value.rs b/crates/toml_edit/src/ser/value.rs
index f0f30401..cc7dfb77 100644
--- a/crates/toml_edit/src/ser/value.rs
+++ b/crates/toml_edit/src/ser/value.rs
@@ -98,7 +98,10 @@ impl serde::ser::Serializer for ValueSerializer {
     }
 
     fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error> {
-        self.serialize_i64(v as i64)
+        let v: i64 = v
+            .try_into()
+            .map_err(|_err| Error::OutOfRange(Some("u64")))?;
+        self.serialize_i64(v)
     }
 
     fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error> {


Test patch:
diff --git a/crates/toml/tests/testsuite/serde.rs b/crates/toml/tests/testsuite/serde.rs
index 8bbff56e..3b9f65a4 100644
--- a/crates/toml/tests/testsuite/serde.rs
+++ b/crates/toml/tests/testsuite/serde.rs
@@ -945,6 +945,20 @@ fn integer_min() {
     }
 }
 
+#[test]
+fn integer_too_big() {
+    #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
+    struct Foo {
+        a_b: u64,
+    }
+
+    let native = Foo { a_b: u64::MAX };
+    let err = Table::try_from(native.clone()).unwrap_err();
+    snapbox::assert_eq("u64 value was too large", err.to_string());
+    let err = toml::to_string(&native).unwrap_err();
+    snapbox::assert_eq("out-of-range value for u64 type", err.to_string());
+}
+
 #[test]
 fn integer_max() {
     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]