diff options
| author | bors <bors@rust-lang.org> | 2019-12-27 18:40:50 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2019-12-27 18:40:50 +0000 |
| commit | 74c4e6a981d3150db8444c8d250e50bbe6b93b6b (patch) | |
| tree | 92c3c5d9924523c0abe79626a417744779353a13 /src/libstd | |
| parent | 41501a6b03a8f10d8c29dfcb37dbd5ff84b33f34 (diff) | |
| parent | 915686d069a36de0a31bc8e4a11d432fed7d4bda (diff) | |
| download | rust-74c4e6a981d3150db8444c8d250e50bbe6b93b6b.tar.gz rust-74c4e6a981d3150db8444c8d250e50bbe6b93b6b.zip | |
Auto merge of #67035 - Goirad:implement-ipadd-padding, r=dtolnay
Implement padding for IpAddr without heap alloc Implements padding for `IpAddr`s without heap allocations. This fixes issue #66810 . cc @jethrogb @mzohreva
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/net/ip.rs | 93 |
1 files changed, 80 insertions, 13 deletions
diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index c170245f493..15d2361acd9 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -9,6 +9,7 @@ use crate::cmp::Ordering; use crate::fmt; use crate::hash; +use crate::io::Write; use crate::sys::net::netc as c; use crate::sys_common::{AsInner, FromInner}; @@ -833,8 +834,16 @@ impl From<Ipv6Addr> for IpAddr { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Ipv4Addr { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + const IPV4_BUF_LEN: usize = 15; // Long enough for the longest possible IPv4 address + let mut buf = [0u8; IPV4_BUF_LEN]; + let mut buf_slice = &mut buf[..]; let octets = self.octets(); - write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]) + // Note: The call to write should never fail, hence the unwrap + write!(buf_slice, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]).unwrap(); + let len = IPV4_BUF_LEN - buf_slice.len(); + // This unsafe is OK because we know what is being written to the buffer + let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; + fmt.pad(buf) } } @@ -1495,18 +1504,40 @@ impl Ipv6Addr { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Ipv6Addr { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + // Note: The calls to write should never fail, hence the unwraps in the function + // Long enough for the longest possible IPv6: 39 + const IPV6_BUF_LEN: usize = 39; + let mut buf = [0u8; IPV6_BUF_LEN]; + let mut buf_slice = &mut buf[..]; + match self.segments() { // We need special cases for :: and ::1, otherwise they're formatted // as ::0.0.0.[01] - [0, 0, 0, 0, 0, 0, 0, 0] => write!(fmt, "::"), - [0, 0, 0, 0, 0, 0, 0, 1] => write!(fmt, "::1"), + [0, 0, 0, 0, 0, 0, 0, 0] => write!(buf_slice, "::").unwrap(), + [0, 0, 0, 0, 0, 0, 0, 1] => write!(buf_slice, "::1").unwrap(), // Ipv4 Compatible address [0, 0, 0, 0, 0, 0, g, h] => { - write!(fmt, "::{}.{}.{}.{}", (g >> 8) as u8, g as u8, (h >> 8) as u8, h as u8) + write!( + buf_slice, + "::{}.{}.{}.{}", + (g >> 8) as u8, + g as u8, + (h >> 8) as u8, + h as u8 + ) + .unwrap(); } // Ipv4-Mapped address [0, 0, 0, 0, 0, 0xffff, g, h] => { - write!(fmt, "::ffff:{}.{}.{}.{}", (g >> 8) as u8, g as u8, (h >> 8) as u8, h as u8) + write!( + buf_slice, + "::ffff:{}.{}.{}.{}", + (g >> 8) as u8, + g as u8, + (h >> 8) as u8, + h as u8 + ) + .unwrap(); } _ => { fn find_zero_slice(segments: &[u16; 8]) -> (usize, usize) { @@ -1539,25 +1570,33 @@ impl fmt::Display for Ipv6Addr { let (zeros_at, zeros_len) = find_zero_slice(&self.segments()); if zeros_len > 1 { - fn fmt_subslice(segments: &[u16], fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fn fmt_subslice(segments: &[u16], buf: &mut &mut [u8]) { if !segments.is_empty() { - write!(fmt, "{:x}", segments[0])?; + write!(*buf, "{:x}", segments[0]).unwrap(); for &seg in &segments[1..] { - write!(fmt, ":{:x}", seg)?; + write!(*buf, ":{:x}", seg).unwrap(); } } - Ok(()) } - fmt_subslice(&self.segments()[..zeros_at], fmt)?; - fmt.write_str("::")?; - fmt_subslice(&self.segments()[zeros_at + zeros_len..], fmt) + fmt_subslice(&self.segments()[..zeros_at], &mut buf_slice); + write!(buf_slice, "::").unwrap(); + fmt_subslice(&self.segments()[zeros_at + zeros_len..], &mut buf_slice); } else { let &[a, b, c, d, e, f, g, h] = &self.segments(); - write!(fmt, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}", a, b, c, d, e, f, g, h) + write!( + buf_slice, + "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}", + a, b, c, d, e, f, g, h + ) + .unwrap(); } } } + let len = IPV6_BUF_LEN - buf_slice.len(); + // This is safe because we know exactly what can be in this buffer + let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; + fmt.pad(buf) } } @@ -1897,6 +1936,18 @@ mod tests { } #[test] + fn ipv4_addr_to_string() { + // Short address + assert_eq!(Ipv4Addr::new(1, 1, 1, 1).to_string(), "1.1.1.1"); + // Long address + assert_eq!(Ipv4Addr::new(127, 127, 127, 127).to_string(), "127.127.127.127"); + + // Test padding + assert_eq!(&format!("{:16}", Ipv4Addr::new(1, 1, 1, 1)), "1.1.1.1 "); + assert_eq!(&format!("{:>16}", Ipv4Addr::new(1, 1, 1, 1)), " 1.1.1.1"); + } + + #[test] fn ipv6_addr_to_string() { // ipv4-mapped address let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280); @@ -1909,6 +1960,22 @@ mod tests { // v6 address with no zero segments assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f"); + // longest possible IPv6 length + assert_eq!( + Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888) + .to_string(), + "1111:2222:3333:4444:5555:6666:7777:8888" + ); + // padding + assert_eq!( + &format!("{:20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), + "1:2:3:4:5:6:7:8 " + ); + assert_eq!( + &format!("{:>20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), + " 1:2:3:4:5:6:7:8" + ); + // reduce a single run of zeros assert_eq!( "ae::ffff:102:304", |
