1use abnf_core::streaming::is_DIGIT;
4use nom::{
5 branch::alt,
6 bytes::streaming::{tag, tag_no_case, take_while1, take_while_m_n},
7 character::is_hex_digit,
8 combinator::{map_res, opt, recognize},
9 multi::{count, many_m_n},
10 sequence::{delimited, tuple},
11 IResult,
12};
13
14use crate::parse::Ldh_str;
15
16pub fn address_literal(input: &[u8]) -> IResult<&[u8], &str> {
23 delimited(
24 tag(b"["),
25 map_res(
26 alt((
27 IPv4_address_literal,
28 IPv6_address_literal,
29 General_address_literal,
30 )),
31 std::str::from_utf8,
32 ),
33 tag(b"]"),
34 )(input)
35}
36
37pub fn IPv4_address_literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
39 let parser = tuple((Snum, count(tuple((tag(b"."), Snum)), 3)));
40
41 let (remaining, parsed) = recognize(parser)(input)?;
42
43 Ok((remaining, parsed))
44}
45
46pub fn Snum(input: &[u8]) -> IResult<&[u8], &[u8]> {
50 take_while_m_n(1, 3, is_DIGIT)(input)
51}
52
53pub fn IPv6_address_literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
55 let parser = tuple((tag_no_case(b"IPv6:"), IPv6_addr));
56
57 let (remaining, parsed) = recognize(parser)(input)?;
58
59 Ok((remaining, parsed))
60}
61
62pub fn IPv6_addr(input: &[u8]) -> IResult<&[u8], &[u8]> {
64 let parser = alt((IPv6_full, IPv6_comp, IPv6v4_full, IPv6v4_comp));
65
66 let (remaining, parsed) = recognize(parser)(input)?;
67
68 Ok((remaining, parsed))
69}
70
71pub fn IPv6_full(input: &[u8]) -> IResult<&[u8], &[u8]> {
73 let parser = tuple((IPv6_hex, count(tuple((tag(b":"), IPv6_hex)), 7)));
74
75 let (remaining, parsed) = recognize(parser)(input)?;
76
77 Ok((remaining, parsed))
78}
79
80pub fn IPv6_hex(input: &[u8]) -> IResult<&[u8], &[u8]> {
82 take_while_m_n(1, 4, is_hex_digit)(input)
83}
84
85pub fn IPv6_comp(input: &[u8]) -> IResult<&[u8], &[u8]> {
90 let parser = tuple((
91 opt(tuple((
92 IPv6_hex,
93 many_m_n(0, 5, tuple((tag(b":"), IPv6_hex))),
94 ))),
95 tag(b"::"),
96 opt(tuple((
97 IPv6_hex,
98 many_m_n(0, 5, tuple((tag(b":"), IPv6_hex))),
99 ))),
100 ));
101
102 let (remaining, parsed) = recognize(parser)(input)?;
103
104 Ok((remaining, parsed))
105}
106
107pub fn IPv6v4_full(input: &[u8]) -> IResult<&[u8], &[u8]> {
109 let parser = tuple((
110 IPv6_hex,
111 count(tuple((tag(b":"), IPv6_hex)), 5),
112 tag(b":"),
113 IPv4_address_literal,
114 ));
115
116 let (remaining, parsed) = recognize(parser)(input)?;
117
118 Ok((remaining, parsed))
119}
120
121pub fn IPv6v4_comp(input: &[u8]) -> IResult<&[u8], &[u8]> {
128 let parser = tuple((
129 opt(tuple((
130 IPv6_hex,
131 many_m_n(0, 3, tuple((tag(b":"), IPv6_hex))),
132 ))),
133 tag(b"::"),
134 opt(tuple((
135 IPv6_hex,
136 many_m_n(0, 3, tuple((tag(b":"), IPv6_hex))),
137 tag(b":"),
138 ))),
139 IPv4_address_literal,
140 ));
141
142 let (remaining, parsed) = recognize(parser)(input)?;
143
144 Ok((remaining, parsed))
145}
146
147pub fn General_address_literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
149 let parser = tuple((Standardized_tag, tag(b":"), take_while1(is_dcontent)));
150
151 let (remaining, parsed) = recognize(parser)(input)?;
152
153 Ok((remaining, parsed))
154}
155
156pub fn Standardized_tag(input: &[u8]) -> IResult<&[u8], &[u8]> {
160 Ldh_str(input)
161}
162
163pub fn is_dcontent(byte: u8) -> bool {
167 matches!(byte, 33..=90 | 94..=126)
168}