Files
addr2line
adler
adler32
ahash
aho_corasick
angle
approx
backtrace
bitflags
blender
bytemuck
byteorder
case
cast_trait
cfg_if
chrono
color
color_quant
const_fn
crc32fast
crossbeam
crossbeam_channel
crossbeam_deque
crossbeam_epoch
crossbeam_queue
crossbeam_skiplist
crossbeam_utils
darling
darling_core
darling_macro
dds
deflate
densevec
derive_builder
derive_builder_core
dot
downcast_rs
dual_quat
either
erased_serde
failure
failure_derive
fixedbitset
float_cmp
fnv
freeimage
freeimage_sys
freetype
freetype_gl_sys
freetype_sys
freetypegl
futures
futures_channel
futures_core
futures_executor
futures_io
futures_macro
futures_sink
futures_task
futures_util
async_await
future
io
lock
sink
stream
task
fxhash
generational_arena
generic_array
getrandom
gif
gimli
glfw
glfw_sys
glin
glin_derive
glsl
half
harfbuzz
harfbuzz_ft_sys
harfbuzz_sys
hashbrown
human_sort
ident_case
image
indexmap
instant
itertools
itoa
jpeg_decoder
lazy_static
libc
libm
lock_api
log
lut_parser
matrixmultiply
memchr
memoffset
meshopt
miniz_oxide
monotonic_clock
mopa
mutiny_derive
na
nalgebra
base
geometry
linalg
ncollide3d
bounding_volume
interpolation
partitioning
pipeline
procedural
query
algorithms
closest_points
contact
distance
nonlinear_time_of_impact
point
proximity
ray
time_of_impact
visitors
shape
transformation
utils
nom
num_complex
num_cpus
num_integer
num_iter
num_rational
num_traits
numext_constructor
numext_fixed_uint
numext_fixed_uint_core
numext_fixed_uint_hack
object
once_cell
parking_lot
parking_lot_core
pathfinding
pennereq
petgraph
pin_project_lite
pin_utils
png
polygon2
ppv_lite86
proc_macro2
proc_macro_crate
proc_macro_hack
proc_macro_nested
quote
rand
rand_chacha
rand_core
rand_distr
raw_window_handle
rawpointer
rayon
rayon_core
rect_packer
regex
regex_syntax
retain_mut
rin
rin_app
rin_blender
rin_core
rin_gl
rin_graphics
rin_gui
rin_material
rin_math
rin_postpo
rin_scene
rin_util
rin_window
rinblender
rinecs
rinecs_derive
rinecs_derive_utils
ringui_derive
rustc_demangle
rusty_pool
ryu
scopeguard
seitan
seitan_derive
semver
semver_parser
serde
serde_derive
serde_json
shaderdata_derive
simba
slab
slice_of_array
slotmap
smallvec
std140_data
streaming_iterator
strsim
syn
synstructure
thiserror
thiserror_impl
thread_local
tiff
time
toml
typenum
unchecked_unwrap
unicode_xid
vec2
vec3
weezl
x11
zlib_sys
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
use version::Identifier;
use recognize::{Recognize, Alt, OneOrMore, Inclusive, OneByte};
use std::str::from_utf8;

// by the time we get here, we know that it's all valid characters, so this doesn't need to return
// a result or anything
fn parse_meta(s: &str) -> Vec<Identifier> {
    // Originally, I wanted to implement this method via calling parse, but parse is tolerant of
    // leading zeroes, and we want anything with leading zeroes to be considered alphanumeric, not
    // numeric. So the strategy is to check with a recognizer first, and then call parse once
    // we've determined that it's a number without a leading zero.
    s.split(".")
        .map(|part| {
            // another wrinkle: we made sure that any number starts with a
            // non-zero. But there's a problem: an actual zero is a number, yet
            // gets left out by this heuristic. So let's also check for the
            // single, lone zero.
            if is_alpha_numeric(part) {
                Identifier::AlphaNumeric(part.to_string())
            } else {
                // we can unwrap here because we know it is only digits due to the regex
                Identifier::Numeric(part.parse().unwrap())
            }
        }).collect()
}

// parse optional metadata (preceded by the prefix character)
pub fn parse_optional_meta(s: &[u8], prefix_char: u8)-> Result<(Vec<Identifier>, usize), String> {
    if let Some(len) = prefix_char.p(s) {
        let start = len;
        if let Some(len) = letters_numbers_dash_dot(&s[start..]) {
            let end = start + len;
            Ok((parse_meta(from_utf8(&s[start..end]).unwrap()), end))
        } else {
            Err("Error parsing prerelease".to_string())
        }
    } else {
        Ok((Vec::new(), 0))
    }
}

pub fn is_alpha_numeric(s: &str) -> bool {
    if let Some((_val, len)) = numeric_identifier(s.as_bytes()) {
        // Return true for number with leading zero
        // Note: doing it this way also handily makes overflow fail over.
        len != s.len()
    } else {
        true
    }
}

// Note: could plumb overflow error up to return value as Result
pub fn numeric_identifier(s: &[u8]) -> Option<(u64, usize)> {
    if let Some(len) = Alt(b'0', OneOrMore(Inclusive(b'0'..b'9'))).p(s) {
        from_utf8(&s[0..len]).unwrap().parse().ok().map(|val| (val, len))
    } else {
        None
    }
}

pub fn letters_numbers_dash_dot(s: &[u8]) -> Option<usize> {
    OneOrMore(OneByte(|c| c == b'-' || c == b'.' ||
        (b'0' <= c && c <= b'9') ||
        (b'a' <= c && c <= b'z') ||
        (b'A' <= c && c <= b'Z'))).p(s)
}