mirror of
https://github.com/vrc-get/vrc-get.git
synced 2026-06-21 09:58:08 +00:00
chore: add customized version
This commit is contained in:
parent
4a1a639cc9
commit
21420e91ab
8 changed files with 387 additions and 160 deletions
|
|
@ -1,7 +1,7 @@
|
|||
use crate::version::Version;
|
||||
use crate::vpm::VersionSelector;
|
||||
use clap::{Parser, Subcommand};
|
||||
use reqwest::Url;
|
||||
use semver::Version;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[derive(Subcommand)]
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use clap::Parser;
|
|||
use reqwest::Client;
|
||||
|
||||
mod commands;
|
||||
mod version;
|
||||
mod vpm;
|
||||
|
||||
#[tokio::main]
|
||||
|
|
|
|||
172
src/version/mod.rs
Normal file
172
src/version/mod.rs
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
pub use range::VersionRange;
|
||||
use std::fmt::{Display, Formatter};
|
||||
pub use version::Version;
|
||||
|
||||
macro_rules! from_str_impl {
|
||||
($ty: ty) => {
|
||||
impl FromStr for $ty {
|
||||
type Err = ParseRangeError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let mut buffer = ParsingBuf::new(s);
|
||||
let result = FromParsingBuf::parse(&mut buffer)?;
|
||||
if buffer.first().is_some() {
|
||||
return Err(ParseRangeError::invalid_char(buffer.first_char()));
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! serialize_to_string {
|
||||
($ty: ty) => {
|
||||
impl ::serde::Serialize for $ty {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: ::serde::Serializer,
|
||||
{
|
||||
serializer.serialize_str(&std::string::ToString::to_string(self))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! deserialize_from_str {
|
||||
($ty: ty, $name: literal) => {
|
||||
impl<'de> ::serde::de::Deserialize<'de> for $ty {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: ::serde::de::Deserializer<'de>,
|
||||
{
|
||||
struct Visitor;
|
||||
impl<'de> ::serde::de::Visitor<'de> for Visitor {
|
||||
type Value = $ty;
|
||||
|
||||
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
|
||||
formatter.write_str($name)
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: ::serde::de::Error,
|
||||
{
|
||||
std::str::FromStr::from_str(v).map_err(E::custom)
|
||||
}
|
||||
}
|
||||
deserializer.deserialize_str(Visitor)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mod range;
|
||||
mod version;
|
||||
|
||||
type Segment = u64;
|
||||
|
||||
const NOT_EXISTS: Segment = Segment::MAX;
|
||||
const STAR: Segment = NOT_EXISTS - 1;
|
||||
const UPPER_X: Segment = STAR - 1;
|
||||
const LOWER_X: Segment = UPPER_X - 1;
|
||||
const VERSION_SEGMENT_MAX: Segment = LOWER_X - 1;
|
||||
|
||||
trait FromParsingBuf: Sized {
|
||||
fn parse(buffer: &mut ParsingBuf) -> Result<Self, ParseRangeError>;
|
||||
}
|
||||
|
||||
struct ParsingBuf<'a> {
|
||||
buf: &'a str,
|
||||
}
|
||||
|
||||
impl<'a> ParsingBuf<'a> {
|
||||
pub fn new(source: &'a str) -> ParsingBuf {
|
||||
Self { buf: source }
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
self.buf.is_empty()
|
||||
}
|
||||
|
||||
pub fn read(&mut self, ch: char) -> Result<(), ParseRangeError> {
|
||||
match self.buf.chars().next() {
|
||||
Some(c) if c == ch => {
|
||||
self.skip();
|
||||
Ok(())
|
||||
}
|
||||
Some(c) => Err(ParseRangeError::invalid_char(c)),
|
||||
None => Err(ParseRangeError::unexpected_end()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn first(&self) -> Option<u8> {
|
||||
self.buf.as_bytes().first().copied()
|
||||
}
|
||||
|
||||
pub fn first_char(&self) -> char {
|
||||
self.buf.chars().next().expect("invalid state")
|
||||
}
|
||||
|
||||
pub fn skip(&mut self) -> &mut Self {
|
||||
if self.buf.len() != 0 {
|
||||
self.buf = &self.buf[1..];
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn get(&self, index: usize) -> Option<u8> {
|
||||
self.buf.as_bytes().get(index).copied()
|
||||
}
|
||||
|
||||
pub fn slip_ws(&mut self) {
|
||||
self.buf = self.buf.trim_start();
|
||||
}
|
||||
|
||||
pub fn take(&mut self, count: usize) -> &str {
|
||||
let (a, b) = self.buf.split_at(count);
|
||||
self.buf = b;
|
||||
a
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ParseRangeError {
|
||||
inner: Inner,
|
||||
}
|
||||
|
||||
impl Display for ParseRangeError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self.inner {
|
||||
Inner::VersionSegmentTooBig => f.write_str("version segment too big"),
|
||||
Inner::UnexpectedEnd => f.write_str("unexpected end"),
|
||||
Inner::InvalidChar(c) => write!(f, "invalid char: {:?}", c),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for ParseRangeError {}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Inner {
|
||||
VersionSegmentTooBig,
|
||||
UnexpectedEnd,
|
||||
InvalidChar(char),
|
||||
}
|
||||
|
||||
impl ParseRangeError {
|
||||
fn too_big() -> Self {
|
||||
Self {
|
||||
inner: Inner::VersionSegmentTooBig,
|
||||
}
|
||||
}
|
||||
fn invalid_char(c: char) -> Self {
|
||||
Self {
|
||||
inner: Inner::InvalidChar(c),
|
||||
}
|
||||
}
|
||||
fn unexpected_end() -> ParseRangeError {
|
||||
Self {
|
||||
inner: Inner::UnexpectedEnd,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,5 @@
|
|||
use crate::vpm::version::{FromParsingBuf, ParseRangeError, ParsingBuf};
|
||||
use semver::{BuildMetadata, Prerelease, Version};
|
||||
use serde::de;
|
||||
use serde::de::Error;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use crate::version::*;
|
||||
use semver::{BuildMetadata, Prerelease};
|
||||
use std::fmt::{Display, Formatter, Write};
|
||||
use std::str::FromStr;
|
||||
|
||||
|
|
@ -20,38 +17,8 @@ impl VersionRange {
|
|||
}
|
||||
}
|
||||
|
||||
impl Serialize for VersionRange {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for VersionRange {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct Visitor;
|
||||
impl<'de> de::Visitor<'de> for Visitor {
|
||||
type Value = VersionRange;
|
||||
|
||||
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("version range")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
VersionRange::from_str(v).map_err(E::custom)
|
||||
}
|
||||
}
|
||||
deserializer.deserialize_str(Visitor)
|
||||
}
|
||||
}
|
||||
serialize_to_string!(VersionRange);
|
||||
deserialize_from_str!(VersionRange, "version range");
|
||||
|
||||
impl Display for VersionRange {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
|
|
@ -99,18 +66,7 @@ impl Display for ComparatorSet {
|
|||
}
|
||||
}
|
||||
|
||||
impl FromStr for ComparatorSet {
|
||||
type Err = ParseRangeError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let mut buffer = ParsingBuf::new(s);
|
||||
let result = FromParsingBuf::parse(&mut buffer)?;
|
||||
if buffer.first().is_some() {
|
||||
return Err(ParseRangeError::invalid_char(buffer.first_char()));
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
from_str_impl!(ComparatorSet);
|
||||
|
||||
impl FromParsingBuf for ComparatorSet {
|
||||
fn parse(buffer: &mut ParsingBuf) -> Result<Self, ParseRangeError> {
|
||||
|
|
@ -248,7 +204,7 @@ impl Comparator {
|
|||
Some(v) => version >= &v,
|
||||
None => {
|
||||
let zeros = v.to_zeros();
|
||||
version >= &zeros || !version.pre.is_empty() && base_version(version) == zeros
|
||||
version >= &zeros || !version.pre.is_empty() && version.base_version() == zeros
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -257,7 +213,8 @@ impl Comparator {
|
|||
Some(v) => version >= &v,
|
||||
None => {
|
||||
let zeros = v.to_zeros();
|
||||
version < &zeros || !(!version.pre.is_empty() && base_version(version) == zeros)
|
||||
version < &zeros
|
||||
|| !(!version.pre.is_empty() && version.base_version() == zeros)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -320,14 +277,6 @@ impl FromParsingBuf for Comparator {
|
|||
}
|
||||
}
|
||||
|
||||
type Segment = u64;
|
||||
|
||||
const NOT_EXISTS: Segment = Segment::MAX;
|
||||
const STAR: Segment = NOT_EXISTS - 1;
|
||||
const UPPER_X: Segment = STAR - 1;
|
||||
const LOWER_X: Segment = UPPER_X - 1;
|
||||
const VERSION_SEGMENT_MAX: Segment = LOWER_X - 1;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct PartialVersion {
|
||||
// MAX_VALUE for not exists
|
||||
|
|
@ -373,10 +322,6 @@ impl Display for PartialVersion {
|
|||
}
|
||||
}
|
||||
|
||||
fn base_version(version: &Version) -> Version {
|
||||
Version::new(version.major, version.minor, version.patch)
|
||||
}
|
||||
|
||||
impl PartialVersion {
|
||||
fn to_full(&self) -> Option<Version> {
|
||||
if let (Some(major), Some(minor), Some(patch)) = (self.major(), self.minor(), self.patch())
|
||||
203
src/version/version.rs
Normal file
203
src/version/version.rs
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
use super::*;
|
||||
use semver::{BuildMetadata, Prerelease};
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt::{Display, Formatter, Write};
|
||||
use std::str::FromStr;
|
||||
|
||||
/// custom version implementation to avoid compare build meta
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Version {
|
||||
pub major: Segment,
|
||||
pub minor: Segment,
|
||||
pub patch: Segment,
|
||||
pub pre: Prerelease,
|
||||
pub build: BuildMetadata,
|
||||
}
|
||||
|
||||
from_str_impl!(Version);
|
||||
serialize_to_string!(Version);
|
||||
deserialize_from_str!(Version, "version");
|
||||
|
||||
impl Display for Version {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}.{}.{}", self.major, self.minor, self.patch)?;
|
||||
|
||||
if !self.pre.is_empty() {
|
||||
f.write_char('-')?;
|
||||
Display::fmt(&self.pre, f)?;
|
||||
}
|
||||
|
||||
if !self.build.is_empty() {
|
||||
f.write_char('+')?;
|
||||
Display::fmt(&self.build, f)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromParsingBuf for Version {
|
||||
fn parse(bytes: &mut ParsingBuf) -> Result<Self, ParseRangeError> {
|
||||
bytes.slip_ws();
|
||||
let major = parse_segment(bytes)?;
|
||||
bytes.read('.')?;
|
||||
let minor = parse_segment(bytes)?;
|
||||
bytes.read('.')?;
|
||||
let patch = parse_segment(bytes)?;
|
||||
|
||||
let pre = if let Some(b'-') = bytes.first() {
|
||||
bytes.skip();
|
||||
Prerelease::parse(bytes)?
|
||||
} else {
|
||||
Prerelease::EMPTY
|
||||
};
|
||||
|
||||
let build = if let Some(b'+') = bytes.first() {
|
||||
bytes.skip();
|
||||
BuildMetadata::parse(bytes)?
|
||||
} else {
|
||||
BuildMetadata::EMPTY
|
||||
};
|
||||
|
||||
return Ok(Version {
|
||||
major,
|
||||
minor,
|
||||
patch,
|
||||
pre,
|
||||
build,
|
||||
});
|
||||
|
||||
fn parse_segment(bytes: &mut ParsingBuf) -> Result<Segment, ParseRangeError> {
|
||||
match bytes.first() {
|
||||
Some(b'1'..=b'9') => {
|
||||
let mut i = 1;
|
||||
while let Some(b'0'..=b'9') = bytes.get(i) {
|
||||
i += 1;
|
||||
}
|
||||
let str = bytes.take(i);
|
||||
let value = Segment::from_str(str).map_err(|_| ParseRangeError::too_big())?;
|
||||
if value > VERSION_SEGMENT_MAX {
|
||||
return Err(ParseRangeError::too_big());
|
||||
}
|
||||
Ok(value)
|
||||
}
|
||||
Some(b'0') => {
|
||||
bytes.skip();
|
||||
// if 0\d, 0 is invalid char
|
||||
if let Some(b'0'..=b'9') = bytes.first() {
|
||||
return Err(ParseRangeError::invalid_char(bytes.first_char()));
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
Some(_) => Err(ParseRangeError::invalid_char(bytes.first_char())),
|
||||
None => Err(ParseRangeError::unexpected_end()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<Self> for Version {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(Ord::cmp(self, other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Version {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.major
|
||||
.cmp(&other.major)
|
||||
.then_with(|| self.minor.cmp(&other.minor))
|
||||
.then_with(|| self.patch.cmp(&other.patch))
|
||||
.then_with(|| self.pre.cmp(&other.pre))
|
||||
}
|
||||
}
|
||||
|
||||
impl Version {
|
||||
pub fn new(major: Segment, minor: Segment, patch: Segment) -> Version {
|
||||
Version {
|
||||
major,
|
||||
minor,
|
||||
patch,
|
||||
pre: Prerelease::EMPTY,
|
||||
build: BuildMetadata::EMPTY,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn base_version(&self) -> Version {
|
||||
Version::new(self.major, self.minor, self.patch)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromParsingBuf for Prerelease {
|
||||
fn parse(buffer: &mut ParsingBuf) -> Result<Self, ParseRangeError> {
|
||||
Ok(Prerelease::new(parse_id(buffer, false)?).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromParsingBuf for BuildMetadata {
|
||||
fn parse(buffer: &mut ParsingBuf) -> Result<Self, ParseRangeError> {
|
||||
Ok(BuildMetadata::new(parse_id(buffer, true)?).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_id<'a>(
|
||||
bytes: &mut ParsingBuf<'a>,
|
||||
allow_loading_zero: bool,
|
||||
) -> Result<&'a str, ParseRangeError> {
|
||||
let buf = bytes.buf;
|
||||
'outer: loop {
|
||||
let mut leading_zero = false;
|
||||
let mut alphanumeric = false;
|
||||
match bytes.first() {
|
||||
None => return Err(ParseRangeError::unexpected_end()),
|
||||
Some(b'0') => {
|
||||
bytes.skip();
|
||||
leading_zero = true;
|
||||
}
|
||||
Some(b'0'..=b'9') => {
|
||||
bytes.skip();
|
||||
}
|
||||
Some(b'a'..=b'z' | b'A'..=b'Z' | b'-') => {
|
||||
bytes.skip();
|
||||
alphanumeric = true;
|
||||
}
|
||||
Some(b'.') => return Err(ParseRangeError::invalid_char('.')),
|
||||
_ => return Err(ParseRangeError::invalid_char(bytes.first_char())),
|
||||
}
|
||||
'segment: loop {
|
||||
match bytes.first() {
|
||||
Some(b'0'..=b'9') => {
|
||||
bytes.skip();
|
||||
}
|
||||
Some(b'a'..=b'z' | b'A'..=b'Z' | b'-') => {
|
||||
bytes.skip();
|
||||
alphanumeric = true;
|
||||
}
|
||||
Some(b'.') => {
|
||||
bytes.skip();
|
||||
if !allow_loading_zero && alphanumeric && leading_zero {
|
||||
// leading zero is invalid char
|
||||
return Err(ParseRangeError::invalid_char('0'));
|
||||
}
|
||||
|
||||
break 'segment;
|
||||
}
|
||||
_ => {
|
||||
// end of segment
|
||||
if !allow_loading_zero && alphanumeric && leading_zero {
|
||||
// leading zero is invalid char
|
||||
return Err(ParseRangeError::invalid_char('0'));
|
||||
}
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if bytes.buf.len() == 0 {
|
||||
Ok(buf)
|
||||
} else {
|
||||
let len = bytes.buf.as_ptr() as usize - buf.as_ptr() as usize;
|
||||
Ok(&buf[..len])
|
||||
}
|
||||
}
|
||||
|
|
@ -2,16 +2,15 @@
|
|||
//!
|
||||
//! This module might be a separated crate.
|
||||
|
||||
use crate::version::{Version, VersionRange};
|
||||
use crate::vpm::structs::manifest::{VpmDependency, VpmLockedDependency, VpmManifest};
|
||||
use crate::vpm::structs::package::PackageJson;
|
||||
use crate::vpm::structs::repository::{LocalCachedRepository, RemoteRepository};
|
||||
use crate::vpm::structs::setting::UserRepoSetting;
|
||||
use crate::vpm::structs::VersionRange;
|
||||
use crate::vpm::utils::{MapResultExt, PathBufExt};
|
||||
use futures::future::join_all;
|
||||
use indexmap::IndexMap;
|
||||
use reqwest::{Client, IntoUrl, Url};
|
||||
use semver::Version;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::ffi::{OsStr, OsString};
|
||||
|
|
@ -27,7 +26,6 @@ use tokio::io::{AsyncRead, AsyncReadExt, AsyncSeekExt, AsyncWriteExt};
|
|||
|
||||
pub mod structs;
|
||||
mod utils;
|
||||
mod version;
|
||||
|
||||
static VRC_OFFICIAL_URL: &'static str = "https://packages.vrchat.com/official?download";
|
||||
static VRC_CURATED_URL: &'static str = "https://packages.vrchat.com/curated?download";
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
pub use crate::vpm::version::VersionRange;
|
||||
use crate::version::{Version, VersionRange};
|
||||
use indexmap::IndexMap;
|
||||
use semver::Version;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use std::path::PathBuf;
|
||||
|
|
|
|||
|
|
@ -1,91 +0,0 @@
|
|||
pub use range::VersionRange;
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
mod range;
|
||||
|
||||
trait FromParsingBuf: Sized {
|
||||
fn parse(buffer: &mut ParsingBuf) -> Result<Self, ParseRangeError>;
|
||||
}
|
||||
|
||||
struct ParsingBuf<'a> {
|
||||
buf: &'a str,
|
||||
}
|
||||
|
||||
impl<'a> ParsingBuf<'a> {
|
||||
pub fn new(source: &'a str) -> ParsingBuf {
|
||||
Self { buf: source }
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
self.buf.is_empty()
|
||||
}
|
||||
|
||||
pub fn first(&self) -> Option<u8> {
|
||||
self.buf.as_bytes().first().copied()
|
||||
}
|
||||
|
||||
pub fn first_char(&self) -> char {
|
||||
self.buf.chars().next().expect("invalid state")
|
||||
}
|
||||
|
||||
pub fn skip(&mut self) -> &mut Self {
|
||||
if self.buf.len() != 0 {
|
||||
self.buf = &self.buf[1..];
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn get(&self, index: usize) -> Option<u8> {
|
||||
self.buf.as_bytes().get(index).copied()
|
||||
}
|
||||
|
||||
pub fn slip_ws(&mut self) {
|
||||
self.buf = self.buf.trim_start();
|
||||
}
|
||||
|
||||
pub fn take(&mut self, count: usize) -> &str {
|
||||
let (a, b) = self.buf.split_at(count);
|
||||
self.buf = b;
|
||||
a
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ParseRangeError {
|
||||
inner: Inner,
|
||||
}
|
||||
|
||||
impl Display for ParseRangeError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self.inner {
|
||||
Inner::VersionSegmentTooBig => f.write_str("version segment too big"),
|
||||
Inner::UnexpectedEnd => f.write_str("unexpected end"),
|
||||
Inner::InvalidChar(c) => write!(f, "invalid char: {:?}", c),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Inner {
|
||||
VersionSegmentTooBig,
|
||||
UnexpectedEnd,
|
||||
InvalidChar(char),
|
||||
}
|
||||
|
||||
impl ParseRangeError {
|
||||
fn too_big() -> Self {
|
||||
Self {
|
||||
inner: Inner::VersionSegmentTooBig,
|
||||
}
|
||||
}
|
||||
fn invalid_char(c: char) -> Self {
|
||||
Self {
|
||||
inner: Inner::InvalidChar(c),
|
||||
}
|
||||
}
|
||||
fn unexpected_end() -> ParseRangeError {
|
||||
Self {
|
||||
inner: Inner::UnexpectedEnd,
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue