dia_ip_range/
ip_v4_range.rs

1/*
2==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--
3
4Dia-IP-Range
5
6Copyright (C) 2021-2024  Anonymous
7
8There are several releases over multiple years,
9they are listed as ranges, such as: "2021-2024".
10
11This program is free software: you can redistribute it and/or modify
12it under the terms of the GNU Lesser General Public License as published by
13the Free Software Foundation, either version 3 of the License, or
14(at your option) any later version.
15
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19GNU Lesser General Public License for more details.
20
21You should have received a copy of the GNU Lesser General Public License
22along with this program.  If not, see <https://www.gnu.org/licenses/>.
23
24::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--
25*/
26
27//! # IPv4 range
28
29use {
30    core::str::FromStr,
31    crate::{Error, IPv4ComponentRange},
32};
33
34#[cfg(feature="iter")]
35#[doc(cfg(feature="iter"))]
36mod ip_v4_range_iter;
37
38#[cfg(feature="iter")]
39#[doc(cfg(feature="iter"))]
40pub use self::ip_v4_range_iter::*;
41
42/// # IPv4 range
43///
44/// A range can be respresented in string, following these rules:
45///
46/// - Start and end are placed inside one of `[]`, `[)`..., separated by a comma.
47/// - `[` and `]` are inclusive.
48/// - `(` and `)` are exclusive.
49/// - White spaces can be included. They will be ignored by parser.
50/// - Length of the string must be equal to or smaller than 64 bytes. It's for protection against flood attack.
51///
52/// Currently this struct is itself useless. You need to enable feature `iter`, in order to use [`IPv4RangeIter`][struct::IPv4RangeIter].
53///
54/// ## Examples
55///
56/// ```
57/// use {
58///     core::str::FromStr,
59///     dia_ip_range::IPv4Range,
60/// };
61///
62/// assert_eq!(
63///     IPv4Range::from_str("10.0.0.[2,100)")?,
64///     IPv4Range::from((10, 0, 0..=0, 2..100)),
65/// );
66///
67/// # Ok::<_, dia_ip_range::Error>(())
68/// ```
69///
70/// [struct::IPv4RangeIter]: struct.IPv4RangeIter.html
71#[derive(Debug, Eq, PartialEq, Hash, Clone)]
72pub struct IPv4Range {
73    a: IPv4ComponentRange,
74    b: IPv4ComponentRange,
75    c: IPv4ComponentRange,
76    d: IPv4ComponentRange,
77}
78
79impl FromStr for IPv4Range {
80
81    type Err = Error;
82
83    fn from_str(s: &str) -> Result<Self, Self::Err> {
84        const MAX_LEN: usize = 64;
85
86        if s.len() > MAX_LEN {
87            return Err(err!("String is too long, max length supported: {} bytes", MAX_LEN));
88        }
89
90        let mut parts = s.trim().split('.');
91        match (parts.next(), parts.next(), parts.next(), parts.next(), parts.next()) {
92            (Some(a), Some(b), Some(c), Some(d), None) => Ok(Self {
93                a: IPv4ComponentRange::from_str(a)?,
94                b: IPv4ComponentRange::from_str(b)?,
95                c: IPv4ComponentRange::from_str(c)?,
96                d: IPv4ComponentRange::from_str(d)?,
97            }),
98            _ => Err(err!("Invalid IPv4 range: {:?}", s)),
99        }
100    }
101
102}
103
104impl<A, B, C, D> From<(A, B, C, D)> for IPv4Range
105where A: Into<IPv4ComponentRange>, B: Into<IPv4ComponentRange>, C: Into<IPv4ComponentRange>, D: Into<IPv4ComponentRange> {
106
107    fn from((a, b, c, d): (A, B, C, D)) -> Self {
108        Self {
109            a: a.into(),
110            b: b.into(),
111            c: c.into(),
112            d: d.into(),
113        }
114    }
115
116}
117
118#[test]
119fn tests() -> crate::Result<()> {
120    for s in &["0.0.0.0", "[255,255].[255,255].[255,255].[255,255]", "192.168.[0,9].[9,10)", "192.168.[    0   ,9].[9  ,    10)"] {
121        IPv4Range::from_str(s)?;
122    }
123    for s in &["0.0.0", "192.168.[09].[9-10)", "192.168.[    0   ,9.9  ,    10)"] {
124        IPv4Range::from_str(s).unwrap_err();
125    }
126
127    Ok(())
128}