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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//! This module contains multiple parsers. In the next paragraphs, each parser is described.
//!
//! # Parsers
//!
//! ## Original
//!
//! The [`original::Parser`] parses a version, byte by byte (`u8`). It stores a
//! slice of bytes in the Parser struct and cursor is created at the start of the
//! [`original::Parser::parse`] method, which acts as an index pointing to the
//! next token to be parsed.
//!
//! It can be used to parse two- or three-component `major.minor(.patch)` versions,
//! where the patch version may or may not be present.
//!
//! ## Modular
//!
//! The [`modular::Parser`] has an API which is based on the _type state_ pattern.
//! Internally it uses a `Peekable` iterator over bytes (`u8`).
//! The modular parser can parse a version incrementally.
//!
//! It may be used to parse either a two component `major.minor` version, or a three component
//! `major.minor.patch` version, or both.
//!
//! # Example
//!
//! In this example we show a basic example of how the original and modular parsers
//! can be used to parse a [`Version`]. For more detailed examples, see their
//! respective modules.
//!
//! ```
//! // Normally you would only use one of these, not both!
//! use version_number::parsers::original;
//! use version_number::parsers::modular;
//!
//! // As an alternative valid input, we could have used a three component version like `1.64.1`.
//! let two_component_version = "1.64";
//!
//! let original_parser = original::Parser::from_slice(two_component_version.as_bytes());
//! let modular_parser = modular::Parser::from_slice(two_component_version.as_bytes());
//!
//! let original_parsed = original_parser.parse().unwrap();
//! let modular_parsed = modular_parser.parse().unwrap();
//!
//! assert_eq!(original_parsed, modular_parsed );
//! ```
//!

use crate::{BaseVersion, FullVersion, Version};

pub use error::{NumericError, ParserError};

pub mod error;
pub mod modular;
pub mod original;

/// Parse a UTF-8 slice of bytes to a [`Version`].
pub trait VersionParser {
    /// Parse a UTF-8 formatted input buffer, `input` to a [`Version`].
    /// This version may be a [`BaseVersion`], or a [`FullVersion`].
    ///
    /// If the version type is known in advance, or you require a specifically
    /// a base- or full version, you may instead use [`BaseVersionParser::parse_base`]
    /// or [`FullVersionParser::parse_full`].
    fn parse_version<B: AsRef<[u8]>>(&self, input: B) -> Result<Version, ParserError>;
}

/// Parse a UTF-8 slice of bytes to a [`BaseVersion`].
pub trait BaseVersionParser {
    /// Parse a UTF-8 formatted input buffer, `input` to a [`BaseVersion`].
    ///
    /// If you don't know, or care, whether the version consists of two or three components,
    /// you may instead use [`VersionParser::parse_version`].
    fn parse_base<B: AsRef<[u8]>>(&self, input: B) -> Result<BaseVersion, ParserError>;
}

/// Parse a UTF-8 slice of bytes to a [`FullVersion`].
pub trait FullVersionParser {
    /// Parse a UTF-8 formatted input buffer, `input` to a [`FullVersion`].
    ///
    /// If you don't know, or care, whether the version consists of two or three components,
    /// you may instead use [`VersionParser::parse_version`].
    fn parse_full<B: AsRef<[u8]>>(&self, input: B) -> Result<FullVersion, ParserError>;
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parse_version_either() {
        let input = "1.22.33";
        let expected = Version::new_full_version(1, 22, 33);

        let original = original::OriginalParser;
        let v = original.parse_version(input).unwrap();
        assert_eq!(v, expected);

        let modular = modular::ModularParser;
        let v = modular.parse_version(input).unwrap();
        assert_eq!(v, expected);
    }

    fn example_generic<T: VersionParser>(input: &str, p: T) -> Version {
        p.parse_version(input).unwrap()
    }

    #[test]
    fn parse_version_either_generic() {
        let input = "1.22.33";
        let expected = Version::new_full_version(1, 22, 33);

        let v = example_generic(input, original::OriginalParser);
        assert_eq!(v, expected);

        let v = example_generic(input, modular::ModularParser);
        assert_eq!(v, expected);
    }
}