#![cfg_attr(not(feature = "std"), no_std)]
#![deny(
missing_docs,
missing_debug_implementations,
missing_copy_implementations,
trivial_casts,
trivial_numeric_casts,
unsafe_code,
unstable_features,
unused_import_braces,
unused_qualifications
)]
#[derive(Debug)]
#[allow(missing_copy_implementations)]
#[non_exhaustive]
pub enum Error {
MissingName {
pos: usize,
},
MissingVersion {
pos: usize,
},
}
#[cfg(feature = "std")]
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::MissingName { pos } => write!(f, "missing name at approx: {}", pos),
Self::MissingVersion { pos } => write!(f, "missing version at approx: {}", pos),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}
#[derive(Debug, Copy, Clone, PartialEq, Hash, PartialOrd, Eq, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CrateVersion<'a> {
pub name: &'a str,
pub version: &'a str,
}
impl<'a> CrateVersion<'a> {
pub fn try_parse(input: &'a str) -> Result<Self, Error> {
let mut split = 0;
let mut iter = input
.chars()
.rev()
.map(|c| {
split += 1;
c
})
.peekable();
while let Some(c) = iter.next() {
match iter.peek() {
Some('-') if c.is_numeric() => break,
_ => {}
}
}
let midpoint = input.len() - split;
let name = input
.get(..midpoint)
.ok_or_else(|| Error::MissingName { pos: midpoint })?;
let version = input
.get(midpoint + 1..)
.ok_or_else(|| Error::MissingVersion { pos: midpoint + 1 })?;
Ok(CrateVersion { name, version })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse() {
let tests = &[
(
"zstd-sys-1.4.15+zstd.1.4.4",
CrateVersion {
name: "zstd-sys",
version: "1.4.15+zstd.1.4.4",
},
),
(
"winapi-i686-pc-windows-gnu-0.4.0",
CrateVersion {
name: "winapi-i686-pc-windows-gnu",
version: "0.4.0",
},
),
(
"wasi-0.9.0+wasi-snapshot-preview1",
CrateVersion {
name: "wasi",
version: "0.9.0+wasi-snapshot-preview1",
},
),
(
"ppv-lite86-0.2.5",
CrateVersion {
name: "ppv-lite86",
version: "0.2.5",
},
),
(
"log-0.4.8",
CrateVersion {
name: "log",
version: "0.4.8",
},
),
];
for (input, expected) in tests {
let crate_ = CrateVersion::try_parse(input).unwrap();
assert_eq!(crate_, *expected);
}
}
}