about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-08-29 06:34:41 +0200
committerGitHub <noreply@github.com>2022-08-29 06:34:41 +0200
commit52016a10053bcdd6c52b60cdcab8c316d26f4172 (patch)
treee3013a0518523725850f71ffbdf102aa4cca244a /library/std/src
parent1ea4efd0656599f824e2567a5b7a95454f701c03 (diff)
parent8bb4b5f44c8b7c811e2075022e5205f927287e0a (diff)
downloadrust-52016a10053bcdd6c52b60cdcab8c316d26f4172.tar.gz
rust-52016a10053bcdd6c52b60cdcab8c316d26f4172.zip
Rollup merge of #94890 - marmeladema:ip-addr-try-from-bytes, r=joshtriplett
Support parsing IP addresses from a byte string

Fixes #94821

The goal is to be able to parse addresses from a byte string without requiring to do any utf8 validation. Since internally the parser already works on byte strings, this should be possible and I personally already needed this in the past too.

~~I used the proposed approach from the issue by implementing `TryFrom<&'a [u8]>` for all 6 address types (3 ip address types and 3 socket address types). I believe implementing stable traits for stable types is insta-stable so this will probably need an FCP?~~

Switched to an unstable inherent method approach called `parse_ascii` as requested.

cc ``````@jyn514``````
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/net/parser.rs138
1 files changed, 125 insertions, 13 deletions
diff --git a/library/std/src/net/parser.rs b/library/std/src/net/parser.rs
index 069b6609985..a38031c48c8 100644
--- a/library/std/src/net/parser.rs
+++ b/library/std/src/net/parser.rs
@@ -39,8 +39,8 @@ struct Parser<'a> {
 }
 
 impl<'a> Parser<'a> {
-    fn new(input: &'a str) -> Parser<'a> {
-        Parser { state: input.as_bytes() }
+    fn new(input: &'a [u8]) -> Parser<'a> {
+        Parser { state: input }
     }
 
     /// Run a parser, and restore the pre-parse state if it fails.
@@ -273,32 +273,106 @@ impl<'a> Parser<'a> {
     }
 }
 
+impl IpAddr {
+    /// Parse an IP address from a slice of bytes.
+    ///
+    /// ```
+    /// #![feature(addr_parse_ascii)]
+    ///
+    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+    ///
+    /// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
+    /// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+    ///
+    /// assert_eq!(IpAddr::parse_ascii(b"127.0.0.1"), Ok(localhost_v4));
+    /// assert_eq!(IpAddr::parse_ascii(b"::1"), Ok(localhost_v6));
+    /// ```
+    #[unstable(feature = "addr_parse_ascii", issue = "101035")]
+    pub fn parse_ascii(b: &[u8]) -> Result<Self, AddrParseError> {
+        Parser::new(b).parse_with(|p| p.read_ip_addr(), AddrKind::Ip)
+    }
+}
+
 #[stable(feature = "ip_addr", since = "1.7.0")]
 impl FromStr for IpAddr {
     type Err = AddrParseError;
     fn from_str(s: &str) -> Result<IpAddr, AddrParseError> {
-        Parser::new(s).parse_with(|p| p.read_ip_addr(), AddrKind::Ip)
+        Self::parse_ascii(s.as_bytes())
     }
 }
 
-#[stable(feature = "rust1", since = "1.0.0")]
-impl FromStr for Ipv4Addr {
-    type Err = AddrParseError;
-    fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> {
+impl Ipv4Addr {
+    /// Parse an IPv4 address from a slice of bytes.
+    ///
+    /// ```
+    /// #![feature(addr_parse_ascii)]
+    ///
+    /// use std::net::Ipv4Addr;
+    ///
+    /// let localhost = Ipv4Addr::new(127, 0, 0, 1);
+    ///
+    /// assert_eq!(Ipv4Addr::parse_ascii(b"127.0.0.1"), Ok(localhost));
+    /// ```
+    #[unstable(feature = "addr_parse_ascii", issue = "101035")]
+    pub fn parse_ascii(b: &[u8]) -> Result<Self, AddrParseError> {
         // don't try to parse if too long
-        if s.len() > 15 {
+        if b.len() > 15 {
             Err(AddrParseError(AddrKind::Ipv4))
         } else {
-            Parser::new(s).parse_with(|p| p.read_ipv4_addr(), AddrKind::Ipv4)
+            Parser::new(b).parse_with(|p| p.read_ipv4_addr(), AddrKind::Ipv4)
         }
     }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+impl FromStr for Ipv4Addr {
+    type Err = AddrParseError;
+    fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> {
+        Self::parse_ascii(s.as_bytes())
+    }
+}
+
+impl Ipv6Addr {
+    /// Parse an IPv6 address from a slice of bytes.
+    ///
+    /// ```
+    /// #![feature(addr_parse_ascii)]
+    ///
+    /// use std::net::Ipv6Addr;
+    ///
+    /// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+    ///
+    /// assert_eq!(Ipv6Addr::parse_ascii(b"::1"), Ok(localhost));
+    /// ```
+    #[unstable(feature = "addr_parse_ascii", issue = "101035")]
+    pub fn parse_ascii(b: &[u8]) -> Result<Self, AddrParseError> {
+        Parser::new(b).parse_with(|p| p.read_ipv6_addr(), AddrKind::Ipv6)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
 impl FromStr for Ipv6Addr {
     type Err = AddrParseError;
     fn from_str(s: &str) -> Result<Ipv6Addr, AddrParseError> {
-        Parser::new(s).parse_with(|p| p.read_ipv6_addr(), AddrKind::Ipv6)
+        Self::parse_ascii(s.as_bytes())
+    }
+}
+
+impl SocketAddrV4 {
+    /// Parse an IPv4 socket address from a slice of bytes.
+    ///
+    /// ```
+    /// #![feature(addr_parse_ascii)]
+    ///
+    /// use std::net::{Ipv4Addr, SocketAddrV4};
+    ///
+    /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+    ///
+    /// assert_eq!(SocketAddrV4::parse_ascii(b"127.0.0.1:8080"), Ok(socket));
+    /// ```
+    #[unstable(feature = "addr_parse_ascii", issue = "101035")]
+    pub fn parse_ascii(b: &[u8]) -> Result<Self, AddrParseError> {
+        Parser::new(b).parse_with(|p| p.read_socket_addr_v4(), AddrKind::SocketV4)
     }
 }
 
@@ -306,7 +380,25 @@ impl FromStr for Ipv6Addr {
 impl FromStr for SocketAddrV4 {
     type Err = AddrParseError;
     fn from_str(s: &str) -> Result<SocketAddrV4, AddrParseError> {
-        Parser::new(s).parse_with(|p| p.read_socket_addr_v4(), AddrKind::SocketV4)
+        Self::parse_ascii(s.as_bytes())
+    }
+}
+
+impl SocketAddrV6 {
+    /// Parse an IPv6 socket address from a slice of bytes.
+    ///
+    /// ```
+    /// #![feature(addr_parse_ascii)]
+    ///
+    /// use std::net::{Ipv6Addr, SocketAddrV6};
+    ///
+    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+    ///
+    /// assert_eq!(SocketAddrV6::parse_ascii(b"[2001:db8::1]:8080"), Ok(socket));
+    /// ```
+    #[unstable(feature = "addr_parse_ascii", issue = "101035")]
+    pub fn parse_ascii(b: &[u8]) -> Result<Self, AddrParseError> {
+        Parser::new(b).parse_with(|p| p.read_socket_addr_v6(), AddrKind::SocketV6)
     }
 }
 
@@ -314,7 +406,27 @@ impl FromStr for SocketAddrV4 {
 impl FromStr for SocketAddrV6 {
     type Err = AddrParseError;
     fn from_str(s: &str) -> Result<SocketAddrV6, AddrParseError> {
-        Parser::new(s).parse_with(|p| p.read_socket_addr_v6(), AddrKind::SocketV6)
+        Self::parse_ascii(s.as_bytes())
+    }
+}
+
+impl SocketAddr {
+    /// Parse a socket address from a slice of bytes.
+    ///
+    /// ```
+    /// #![feature(addr_parse_ascii)]
+    ///
+    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
+    ///
+    /// let socket_v4 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+    /// let socket_v6 = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), 8080);
+    ///
+    /// assert_eq!(SocketAddr::parse_ascii(b"127.0.0.1:8080"), Ok(socket_v4));
+    /// assert_eq!(SocketAddr::parse_ascii(b"[::1]:8080"), Ok(socket_v6));
+    /// ```
+    #[unstable(feature = "addr_parse_ascii", issue = "101035")]
+    pub fn parse_ascii(b: &[u8]) -> Result<Self, AddrParseError> {
+        Parser::new(b).parse_with(|p| p.read_socket_addr(), AddrKind::Socket)
     }
 }
 
@@ -322,7 +434,7 @@ impl FromStr for SocketAddrV6 {
 impl FromStr for SocketAddr {
     type Err = AddrParseError;
     fn from_str(s: &str) -> Result<SocketAddr, AddrParseError> {
-        Parser::new(s).parse_with(|p| p.read_socket_addr(), AddrKind::Socket)
+        Self::parse_ascii(s.as_bytes())
     }
 }