Repository: dtolnay/semver (Rust)

Issue:
Display impl for Version no longer supports padding
It looks like this used to be supported (#187), but on the latest version (1.0.3), the code from that issue prints 

```
0              .0              .0               0              .0              .0              
```

Playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=dc2af83acd2ef7505ac8a69ec779c563


Discussion:

Patch:
diff --git a/src/display.rs b/src/display.rs
index c3348f92..3c2871bb 100644
--- a/src/display.rs
+++ b/src/display.rs
@@ -1,16 +1,32 @@
 use crate::{BuildMetadata, Comparator, Op, Prerelease, Version, VersionReq};
-use core::fmt::{self, Debug, Display};
+use core::fmt::{self, Alignment, Debug, Display, Write};
 
 impl Display for Version {
     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
-        write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)?;
-        if !self.pre.is_empty() {
-            write!(formatter, "-{}", self.pre)?;
-        }
-        if !self.build.is_empty() {
-            write!(formatter, "+{}", self.build)?;
-        }
-        Ok(())
+        let do_display = |formatter: &mut fmt::Formatter| -> fmt::Result {
+            write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)?;
+            if !self.pre.is_empty() {
+                write!(formatter, "-{}", self.pre)?;
+            }
+            if !self.build.is_empty() {
+                write!(formatter, "+{}", self.build)?;
+            }
+            Ok(())
+        };
+
+        let do_len = || -> usize {
+            digits(self.major)
+                + 1
+                + digits(self.minor)
+                + 1
+                + digits(self.patch)
+                + !self.pre.is_empty() as usize
+                + self.pre.len()
+                + !self.build.is_empty() as usize
+                + self.build.len()
+        };
+
+        pad(formatter, do_display, do_len)
     }
 }
 
@@ -102,3 +118,48 @@ impl Debug for BuildMetadata {
         write!(formatter, "BuildMetadata(\"{}\")", self)
     }
 }
+
+fn pad(
+    formatter: &mut fmt::Formatter,
+    do_display: impl FnOnce(&mut fmt::Formatter) -> fmt::Result,
+    do_len: impl FnOnce() -> usize,
+) -> fmt::Result {
+    let min_width = match formatter.width() {
+        Some(min_width) => min_width,
+        None => return do_display(formatter),
+    };
+
+    let len = do_len();
+    if len >= min_width {
+        return do_display(formatter);
+    }
+
+    let default_align = Alignment::Left;
+    let align = formatter.align().unwrap_or(default_align);
+    let padding = min_width - len;
+    let (pre_pad, post_pad) = match align {
+        Alignment::Left => (0, padding),
+        Alignment::Right => (padding, 0),
+        Alignment::Center => (padding / 2, (padding + 1) / 2),
+    };
+
+    let fill = formatter.fill();
+    for _ in 0..pre_pad {
+        formatter.write_char(fill)?;
+    }
+
+    do_display(formatter)?;
+
+    for _ in 0..post_pad {
+        formatter.write_char(fill)?;
+    }
+    Ok(())
+}
+
+fn digits(val: u64) -> usize {
+    if val < 10 {
+        1
+    } else {
+        1 + digits(val / 10)
+    }
+}


Test patch:
diff --git a/tests/test_version.rs b/tests/test_version.rs
index a8478b0f..c262be79 100644
--- a/tests/test_version.rs
+++ b/tests/test_version.rs
@@ -225,3 +225,11 @@ fn test_spec_order() {
         i += 1;
     }
 }
+
+#[test]
+fn test_align() {
+    let version = version("1.2.3-rc1");
+    assert_eq!("1.2.3-rc1           ", format!("{:20}", version));
+    assert_eq!("*****1.2.3-rc1******", format!("{:*^20}", version));
+    assert_eq!("           1.2.3-rc1", format!("{:>20}", version));
+}