Repository: Nukesor/comfy-table (rust)

Issue:
[Bug] Integer overflow on large column
### Describe the bug

It was initially reported here. 

https://github.com/apache/arrow-datafusion/issues/6524

Padding uses `u16`; It caused integer overflow on large table.

I wonder if it would be possible to allow users to check how big the table is going to be so that it can avoid causing overflow.

Proposed changes:

1. Wrap returning result with `Result<_, ComfyTableError>`
This ones fixes the issue but it causes braking changes.

2. Change `u16` to `u64`
It should be less-likely for this to happen.

I implemented `1.` on my fork, so if you are moving forward with `1`, I'd love to create a PR.

### Steps to reproduce

Details in the `arrow-datafusion` issue.

### Logs (if applicable)

Details in the `arrow-datafusion` issue.

### Operating system

NA

### Comfy-table version

v6.1.4

### Additional context

_No response_

Pull request description:
Fix overflow in several places
Resolves #112 

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 468335a..5baeee7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.
 
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
+## [7.0.1] - unreleased
+
+## Fix
+
+- Fix a panic when working with extreme paddings, where `(padding.left + padding.right) > u16::MAX`.
+- Fix a panic when working with extremely long content, where `(content_width + padding) > u16::MAX`.
+
 ## [7.0.0] - 2023-06-06
 
 ### Breaking
diff --git a/src/column.rs b/src/column.rs
index ac7f734..742fac9 100644
--- a/src/column.rs
+++ b/src/column.rs
@@ -62,9 +62,9 @@ impl Column {
         self
     }
 
-    /// Internal convenience helper that returns the total width of the combined padding.
-    pub(crate) fn padding_width(&self) -> u16 {
-        self.padding.0 + self.padding.1
+    /// Convenience helper that returns the total width of the combined padding.
+    pub fn padding_width(&self) -> u16 {
+        self.padding.0.saturating_add(self.padding.1)
     }
 
     /// Set the delimiter used to split text for this column's cells.
diff --git a/src/utils/arrangement/helper.rs b/src/utils/arrangement/helper.rs
index 6994f0b..43866b8 100644
--- a/src/utils/arrangement/helper.rs
+++ b/src/utils/arrangement/helper.rs
@@ -11,13 +11,14 @@ use crate::{Cell, Column, Table};
 /// For this reason, we take the targeted width, subtract the column's padding and make sure that
 /// the content width is always a minimum of 1
 pub fn absolute_width_with_padding(column: &Column, width: u16) -> u16 {
-    let (left, right) = column.padding;
-    let mut content_width = i32::from(width) - i32::from(left) - i32::from(right);
-    if content_width <= 0 {
+    let mut content_width = width
+        .saturating_sub(column.padding.0)
+        .saturating_sub(column.padding.1);
+    if content_width == 0 {
         content_width = 1;
     }
 
-    content_width.try_into().unwrap_or(u16::MAX)
+    content_width
 }
 
 /// Return the amount of visible columns
diff --git a/src/utils/mod.rs b/src/utils/mod.rs
index 61fb250..ff6ea62 100644
--- a/src/utils/mod.rs
+++ b/src/utils/mod.rs
@@ -41,7 +41,9 @@ impl ColumnDisplayInfo {
     }
 
     pub fn width(&self) -> u16 {
-        self.content_width + self.padding.0 + self.padding.1
+        self.content_width
+            .saturating_add(self.padding.0)
+            .saturating_add(self.padding.1)
     }
 }
 


Test patch:
diff --git a/tests/all/edge_cases.rs b/tests/all/edge_cases.rs
new file mode 100644
index 0000000..4771843
--- /dev/null
+++ b/tests/all/edge_cases.rs
@@ -0,0 +1,23 @@
+use comfy_table::*;
+
+/// A gigantic table can generated, even if it's longer than the longest supported width.
+#[test]
+fn giant_table() {
+    let mut table = Table::new();
+    table.set_header(["a".repeat(1_000_000)]);
+    table.add_row(["a".repeat(1_000_000)]);
+
+    table.to_string();
+}
+
+/// No panic, even if there's a ridiculous amount of padding.
+#[test]
+fn max_padding() {
+    let mut table = Table::new();
+    table.add_row(["test"]);
+    let column = table.column_mut(0).unwrap();
+
+    column.set_padding((u16::MAX, u16::MAX));
+
+    table.to_string();
+}
diff --git a/tests/all/mod.rs b/tests/all/mod.rs
index 53055d8..29f4d2d 100644
--- a/tests/all/mod.rs
+++ b/tests/all/mod.rs
@@ -8,6 +8,7 @@ mod combined_test;
 mod constraints_test;
 mod content_arrangement_test;
 mod custom_delimiter_test;
+mod edge_cases;
 mod hidden_test;
 #[cfg(feature = "custom_styling")]
 mod inner_style_test;