Revision control
Copy as Markdown
Other Tools
use crate::{BuildMetadata, Comparator, Op, Prerelease, Version, VersionReq};
use core::fmt::{self, Alignment, Debug, Display, Write};
impl Display for Version {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
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)
}
}
impl Display for VersionReq {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
if self.comparators.is_empty() {
return formatter.write_str("*");
}
for (i, comparator) in self.comparators.iter().enumerate() {
if i > 0 {
formatter.write_str(", ")?;
}
write!(formatter, "{}", comparator)?;
}
Ok(())
}
}
impl Display for Comparator {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
let op = match self.op {
Op::Exact => "=",
Op::Greater => ">",
Op::GreaterEq => ">=",
Op::Less => "<",
Op::LessEq => "<=",
Op::Tilde => "~",
Op::Caret => "^",
Op::Wildcard => "",
#[cfg(no_non_exhaustive)]
Op::__NonExhaustive => unreachable!(),
};
formatter.write_str(op)?;
write!(formatter, "{}", self.major)?;
if let Some(minor) = &self.minor {
write!(formatter, ".{}", minor)?;
if let Some(patch) = &self.patch {
write!(formatter, ".{}", patch)?;
if !self.pre.is_empty() {
write!(formatter, "-{}", self.pre)?;
}
} else if self.op == Op::Wildcard {
formatter.write_str(".*")?;
}
} else if self.op == Op::Wildcard {
formatter.write_str(".*")?;
}
Ok(())
}
}
impl Display for Prerelease {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(self.as_str())
}
}
impl Display for BuildMetadata {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(self.as_str())
}
}
impl Debug for Version {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
let mut debug = formatter.debug_struct("Version");
debug
.field("major", &self.major)
.field("minor", &self.minor)
.field("patch", &self.patch);
if !self.pre.is_empty() {
debug.field("pre", &self.pre);
}
if !self.build.is_empty() {
debug.field("build", &self.build);
}
debug.finish()
}
}
impl Debug for Prerelease {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "Prerelease(\"{}\")", self)
}
}
impl Debug for BuildMetadata {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
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)
}
}