Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 8 pull requests #77544

Closed
wants to merge 23 commits into from
Closed
Changes from 3 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
badf4af
core::global_allocator docs link to std::alloc::GlobalAlloc
mightyiam Sep 26, 2020
df76cf8
BTreeMap: admit the existence of leaf edges in comments
ssomers Aug 9, 2020
d71d13e
BTreeMap: refactoring around edges, missed spots
ssomers Sep 26, 2020
0e68e1b
Prevent #[doc(alias = "...")] at crate level
GuillaumeGomez Sep 4, 2020
5c836e3
Add test for #[doc(alias = "...")] at crate level
GuillaumeGomez Sep 4, 2020
0e18017
Ensure that the error isn't displayed more than once
GuillaumeGomez Sep 11, 2020
3950a6d
Run attributes check at crate level
GuillaumeGomez Sep 21, 2020
6ec2474
Strenghten tests for crate-level attributes check
GuillaumeGomez Sep 29, 2020
3d17eb3
Update to chalk 0.31. Implement some unimplemented. Ignore some tests…
jackh726 Oct 4, 2020
3641a37
Enforce crate level attributes checks
GuillaumeGomez Oct 3, 2020
4585c22
Include scope id in SocketAddrV6::Display
tamird Oct 1, 2020
b4e77d2
rewrite old test so that its attributes are consistent with what we w…
pnkfelix Jun 15, 2020
9601724
Avoid unchecked casts in net parser
tamird Oct 4, 2020
f78a7ad
Inline "eof" methods
tamird Oct 4, 2020
afa2a67
Prevent forbid from being ignored if overriden at the same level.
pnkfelix Jun 15, 2020
61fbf53
Rollup merge of #76329 - GuillaumeGomez:doc-alias-crate-level, r=matt…
jonas-schievink Oct 4, 2020
4268859
Rollup merge of #77219 - mightyiam:issue_77100, r=jyn514
jonas-schievink Oct 4, 2020
9434988
Rollup merge of #77395 - ssomers:btree_love_the_leaf_edge_comments, r…
jonas-schievink Oct 4, 2020
1c397b9
Rollup merge of #77426 - tamird:sockaddr-scope-id, r=dtolnay
jonas-schievink Oct 4, 2020
ba5d93d
Rollup merge of #77471 - ssomers:btree_cleanup_3, r=Mark-Simulacrum
jonas-schievink Oct 4, 2020
ce5455e
Rollup merge of #77515 - jackh726:chalk-0.31, r=matthewjasper
jonas-schievink Oct 4, 2020
bdd34bc
Rollup merge of #77528 - tamird:avoid-cast-net-parser, r=dtolnay
jonas-schievink Oct 4, 2020
04fcbc7
Rollup merge of #77534 - Mark-Simulacrum:issue-70819-disallow-overrid…
jonas-schievink Oct 4, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 48 additions & 36 deletions library/std/src/net/parser.rs
Original file line number Diff line number Diff line change
@@ -6,11 +6,34 @@
#[cfg(test)]
mod tests;

use crate::convert::TryInto as _;
use crate::error::Error;
use crate::fmt;
use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use crate::str::FromStr;

trait ReadNumberHelper: crate::marker::Sized {
const ZERO: Self;
fn checked_mul(&self, other: u32) -> Option<Self>;
fn checked_add(&self, other: u32) -> Option<Self>;
}

macro_rules! impl_helper {
($($t:ty)*) => ($(impl ReadNumberHelper for $t {
const ZERO: Self = 0;
#[inline]
fn checked_mul(&self, other: u32) -> Option<Self> {
Self::checked_mul(*self, other.try_into().ok()?)
}
#[inline]
fn checked_add(&self, other: u32) -> Option<Self> {
Self::checked_add(*self, other.try_into().ok()?)
}
})*)
}

impl_helper! { u8 u16 }

struct Parser<'a> {
// parsing as ASCII, so can use byte array
state: &'a [u8],
@@ -21,10 +44,6 @@ impl<'a> Parser<'a> {
Parser { state: input.as_bytes() }
}

fn is_eof(&self) -> bool {
self.state.is_empty()
}

/// Run a parser, and restore the pre-parse state if it fails
fn read_atomically<T, F>(&mut self, inner: F) -> Option<T>
where
@@ -40,26 +59,19 @@ impl<'a> Parser<'a> {

/// Run a parser, but fail if the entire input wasn't consumed.
/// Doesn't run atomically.
fn read_till_eof<T, F>(&mut self, inner: F) -> Option<T>
where
F: FnOnce(&mut Parser<'_>) -> Option<T>,
{
inner(self).filter(|_| self.is_eof())
}

/// Same as read_till_eof, but returns a Result<AddrParseError> on failure
fn parse_with<T, F>(&mut self, inner: F) -> Result<T, AddrParseError>
where
F: FnOnce(&mut Parser<'_>) -> Option<T>,
{
self.read_till_eof(inner).ok_or(AddrParseError(()))
let result = inner(self);
if self.state.is_empty() { result } else { None }.ok_or(AddrParseError(()))
}

/// Read the next character from the input
fn read_char(&mut self) -> Option<char> {
self.state.split_first().map(|(&b, tail)| {
self.state = tail;
b as char
char::from(b)
})
}

@@ -84,25 +96,26 @@ impl<'a> Parser<'a> {
})
}

// Read a single digit in the given radix. For instance, 0-9 in radix 10;
// 0-9A-F in radix 16.
fn read_digit(&mut self, radix: u32) -> Option<u32> {
self.read_atomically(move |p| p.read_char()?.to_digit(radix))
}

// Read a number off the front of the input in the given radix, stopping
// at the first non-digit character or eof. Fails if the number has more
// digits than max_digits, or the value is >= upto, or if there is no number.
fn read_number(&mut self, radix: u32, max_digits: u32, upto: u32) -> Option<u32> {
// digits than max_digits or if there is no number.
fn read_number<T: ReadNumberHelper>(
&mut self,
radix: u32,
max_digits: Option<usize>,
) -> Option<T> {
self.read_atomically(move |p| {
let mut result = 0;
let mut result = T::ZERO;
let mut digit_count = 0;

while let Some(digit) = p.read_digit(radix) {
result = (result * radix) + digit;
while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) {
result = result.checked_mul(radix)?;
result = result.checked_add(digit)?;
digit_count += 1;
if digit_count > max_digits || result >= upto {
return None;
if let Some(max_digits) = max_digits {
if digit_count > max_digits {
return None;
}
}
}

@@ -116,7 +129,7 @@ impl<'a> Parser<'a> {
let mut groups = [0; 4];

for (i, slot) in groups.iter_mut().enumerate() {
*slot = p.read_separator('.', i, |p| p.read_number(10, 3, 0x100))? as u8;
*slot = p.read_separator('.', i, |p| p.read_number(10, None))?;
}

Some(groups.into())
@@ -140,17 +153,17 @@ impl<'a> Parser<'a> {
let ipv4 = p.read_separator(':', i, |p| p.read_ipv4_addr());

if let Some(v4_addr) = ipv4 {
let octets = v4_addr.octets();
groups[i + 0] = ((octets[0] as u16) << 8) | (octets[1] as u16);
groups[i + 1] = ((octets[2] as u16) << 8) | (octets[3] as u16);
let [one, two, three, four] = v4_addr.octets();
groups[i + 0] = u16::from_be_bytes([one, two]);
groups[i + 1] = u16::from_be_bytes([three, four]);
return (i + 2, true);
}
}

let group = p.read_separator(':', i, |p| p.read_number(16, 4, 0x10000));
let group = p.read_separator(':', i, |p| p.read_number(16, Some(4)));

match group {
Some(g) => *slot = g as u16,
Some(g) => *slot = g,
None => return (i, false),
}
}
@@ -195,12 +208,11 @@ impl<'a> Parser<'a> {
self.read_ipv4_addr().map(IpAddr::V4).or_else(move || self.read_ipv6_addr().map(IpAddr::V6))
}

/// Read a : followed by a port in base 10
/// Read a : followed by a port in base 10.
fn read_port(&mut self) -> Option<u16> {
self.read_atomically(|p| {
let _ = p.read_given_char(':')?;
let port = p.read_number(10, 5, 0x10000)?;
Some(port as u16)
p.read_number(10, None)
})
}