semver/
display.rs

1use crate::{BuildMetadata, Comparator, Op, Prerelease, Version, VersionReq};
2use core::fmt::{self, Alignment, Debug, Display, Write};
3
4impl Display for Version {
5    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
6        let do_display = |formatter: &mut fmt::Formatter| -> fmt::Result {
7            write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)?;
8            if !self.pre.is_empty() {
9                write!(formatter, "-{}", self.pre)?;
10            }
11            if !self.build.is_empty() {
12                write!(formatter, "+{}", self.build)?;
13            }
14            Ok(())
15        };
16
17        let do_len = || -> usize {
18            digits(self.major)
19                + 1
20                + digits(self.minor)
21                + 1
22                + digits(self.patch)
23                + !self.pre.is_empty() as usize
24                + self.pre.len()
25                + !self.build.is_empty() as usize
26                + self.build.len()
27        };
28
29        pad(formatter, do_display, do_len)
30    }
31}
32
33impl Display for VersionReq {
34    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
35        if self.comparators.is_empty() {
36            return formatter.write_str("*");
37        }
38        for (i, comparator) in self.comparators.iter().enumerate() {
39            if i > 0 {
40                formatter.write_str(", ")?;
41            }
42            write!(formatter, "{}", comparator)?;
43        }
44        Ok(())
45    }
46}
47
48impl Display for Comparator {
49    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
50        let op = match self.op {
51            Op::Exact => "=",
52            Op::Greater => ">",
53            Op::GreaterEq => ">=",
54            Op::Less => "<",
55            Op::LessEq => "<=",
56            Op::Tilde => "~",
57            Op::Caret => "^",
58            Op::Wildcard => "",
59        };
60        formatter.write_str(op)?;
61        write!(formatter, "{}", self.major)?;
62        if let Some(minor) = &self.minor {
63            write!(formatter, ".{}", minor)?;
64            if let Some(patch) = &self.patch {
65                write!(formatter, ".{}", patch)?;
66                if !self.pre.is_empty() {
67                    write!(formatter, "-{}", self.pre)?;
68                }
69            } else if self.op == Op::Wildcard {
70                formatter.write_str(".*")?;
71            }
72        } else if self.op == Op::Wildcard {
73            formatter.write_str(".*")?;
74        }
75        Ok(())
76    }
77}
78
79impl Display for Prerelease {
80    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
81        formatter.write_str(self.as_str())
82    }
83}
84
85impl Display for BuildMetadata {
86    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
87        formatter.write_str(self.as_str())
88    }
89}
90
91impl Debug for Version {
92    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
93        let mut debug = formatter.debug_struct("Version");
94        debug
95            .field("major", &self.major)
96            .field("minor", &self.minor)
97            .field("patch", &self.patch);
98        if !self.pre.is_empty() {
99            debug.field("pre", &self.pre);
100        }
101        if !self.build.is_empty() {
102            debug.field("build", &self.build);
103        }
104        debug.finish()
105    }
106}
107
108impl Debug for Prerelease {
109    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
110        write!(formatter, "Prerelease(\"{}\")", self)
111    }
112}
113
114impl Debug for BuildMetadata {
115    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
116        write!(formatter, "BuildMetadata(\"{}\")", self)
117    }
118}
119
120fn pad(
121    formatter: &mut fmt::Formatter,
122    do_display: impl FnOnce(&mut fmt::Formatter) -> fmt::Result,
123    do_len: impl FnOnce() -> usize,
124) -> fmt::Result {
125    let min_width = match formatter.width() {
126        Some(min_width) => min_width,
127        None => return do_display(formatter),
128    };
129
130    let len = do_len();
131    if len >= min_width {
132        return do_display(formatter);
133    }
134
135    let default_align = Alignment::Left;
136    let align = formatter.align().unwrap_or(default_align);
137    let padding = min_width - len;
138    let (pre_pad, post_pad) = match align {
139        Alignment::Left => (0, padding),
140        Alignment::Right => (padding, 0),
141        Alignment::Center => (padding / 2, (padding + 1) / 2),
142    };
143
144    let fill = formatter.fill();
145    for _ in 0..pre_pad {
146        formatter.write_char(fill)?;
147    }
148
149    do_display(formatter)?;
150
151    for _ in 0..post_pad {
152        formatter.write_char(fill)?;
153    }
154    Ok(())
155}
156
157fn digits(val: u64) -> usize {
158    if val < 10 {
159        1
160    } else {
161        1 + digits(val / 10)
162    }
163}