Change:
} } <ins> 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) } } </ins> #[stable(feature = "ip_addr", since = "1.7.0")] impl FromStr for IpAddr { type Err = AddrParseError; fn from_str(s: &str) -> Result<IpAddr, AddrParseError> { <del> Parser::new(s).parse_with(|p| p.read_ip_addr(), AddrKind::Ip) </del> <ins> Self::parse_ascii(s.as_bytes()) </ins> } } <del> #[stable(feature = "rust1", since = "1.0.0")] impl FromStr for Ipv4Addr { type Err = AddrParseError; fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> { </del> <ins> 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> { </ins> // don't try to parse if too long <del> if s.len() > 15 { </del> <ins> if b.len() > 15 { </ins> Err(AddrParseError(AddrKind::Ipv4)) } else { <del> Parser::new(s).parse_with(|p| p.read_ipv4_addr(), AddrKind::Ipv4) </del> <ins> Parser::new(b).parse_with(|p| p.read_ipv4_addr(), AddrKind::Ipv4) </ins> } } } #[stable(feature = "rust1", since = "1.0.0")] <ins> 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")] </ins> impl FromStr for Ipv6Addr { type Err = AddrParseError; fn from_str(s: &str) -> Result<Ipv6Addr, AddrParseError> { <del> Parser::new(s).parse_with(|p| p.read_ipv6_addr(), AddrKind::Ipv6) </del> <ins> 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) </ins> } }

Discussion:
The only standard way I've found to parse an IP address is . That function immediately converts the string to bytes: It would be great to expose some way (not necessarily , but something similar) that doesn't require doing unnecessary utf8 validation. label: +T-libs +C-enhancement <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOT_END --
Hi where is the utf8 validation happening? As you said, the string slice gets converted to a byte slice but then it looks like the parser just works with s which get cast to s at some points in the algorithm
it happens before you ever pass the string to : I have a byte sequence, and in order to parse it, I'm forced to call .
implements for arrays [u8; 4] and [u8; 16]
I don't have an array. I have a dynamically sized &[u8], and I'm not sure whether it's a valid IP address or not.
Gotcha. If this is a valid ipv6 address (so it has at least 16 bytes) but the first four bytes make up a valid ipv4 address too then we'd have to make a decision. We could require that the be of size 4 or 16 then we'd know how to interpret it?
claim
4 and 16 are misleading I think. This is a normal IP address, like "127.0.0.1", it just happens to have come from the network and not be utf8 validated. "127.0.0.1" is 9 bytes, and in general, IP addresses can be variable length.
If the address, say "127.0.0.1", comes from the network, as inside an IPv4 header, then it must be a 32 bit value, it would be of the form but utf8 encoded IP addresses would have variable length as you said so maybe that is what you're referring to receiving on the network?
We could add something like this and add in the docs that this parses IP addresses and assumes that they're utf8 encoded?
It doesn't.

No part of that code requires to be utf8 encoded - if it contains a non-utf8 byte, then it's not a valid IP address anyway, and it returns like normal.
I disagree. The slice of bytes must represent an IP address string in dot notation so the slice of bytes "encodes" this string; some comment should be to the docs to explain what the slice of bytes is. For instance, this slice of bytes is bad and would cause a parse error. It doesn't contain non-utf8 byte but it doesn't encode an IP address string in dot notation. instead it should be This is what does - we get the underlying bytes encoding the string.
Oh, I see what you mean - you're saying that it should be a byte string, and not an array of the ip numbers. Yes, I agree that's what the code is doing.
So is this issue for exposing a new way to parse ip byte strings or a slice of the ip numbers? Not sure how to move forward. Thanks for working with me on this btw.
I don't understand the question. I have and I want to turn it into an IpAddr.
This made me think that you were taking about an array/slice of the numbers of the ip address and not a byte string. Actually, I'm gonna let someone else have a crack at this. There's some useful info here and enough to get started. release-assignment