Skip to main content

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            formatter.write_fmt(format_args!("{0}.{1}.{2}", self.major, self.minor,
        self.patch))write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)?;
8            if !self.pre.is_empty() {
9                formatter.write_fmt(format_args!("-{0}", self.pre))write!(formatter, "-{}", self.pre)?;
10            }
11            if !self.build.is_empty() {
12                formatter.write_fmt(format_args!("+{0}", self.build))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            formatter.write_fmt(format_args!("{0}", comparator))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        formatter.write_fmt(format_args!("{0}", self.major))write!(formatter, "{}", self.major)?;
62        if let Some(minor) = &self.minor {
63            formatter.write_fmt(format_args!(".{0}", minor))write!(formatter, ".{}", minor)?;
64            if let Some(patch) = &self.patch {
65                formatter.write_fmt(format_args!(".{0}", patch))write!(formatter, ".{}", patch)?;
66                if !self.pre.is_empty() {
67                    formatter.write_fmt(format_args!("-{0}", self.pre))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        formatter.write_fmt(format_args!("Prerelease(\"{0}\")", self))write!(formatter, "Prerelease(\"{}\")", self)
111    }
112}
113
114impl Debug for BuildMetadata {
115    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
116        formatter.write_fmt(format_args!("BuildMetadata(\"{0}\")", self))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 Some(min_width) = formatter.width() else {
126        return do_display(formatter);
127    };
128
129    let len = do_len();
130    if len >= min_width {
131        return do_display(formatter);
132    }
133
134    let default_align = Alignment::Left;
135    let align = formatter.align().unwrap_or(default_align);
136    let padding = min_width - len;
137    let (pre_pad, post_pad) = match align {
138        Alignment::Left => (0, padding),
139        Alignment::Right => (padding, 0),
140        Alignment::Center => (padding / 2, (padding + 1) / 2),
141    };
142
143    let fill = formatter.fill();
144    for _ in 0..pre_pad {
145        formatter.write_char(fill)?;
146    }
147
148    do_display(formatter)?;
149
150    for _ in 0..post_pad {
151        formatter.write_char(fill)?;
152    }
153    Ok(())
154}
155
156fn digits(val: u64) -> usize {
157    if val < 10 {
158        1
159    } else {
160        1 + digits(val / 10)
161    }
162}