Skip to content

Commit 74c4e6a

Browse files
committed
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
2 parents 41501a6 + 915686d commit 74c4e6a

File tree

1 file changed

+80
-13
lines changed

1 file changed

+80
-13
lines changed

src/libstd/net/ip.rs

+80-13
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use crate::cmp::Ordering;
1010
use crate::fmt;
1111
use crate::hash;
12+
use crate::io::Write;
1213
use crate::sys::net::netc as c;
1314
use crate::sys_common::{AsInner, FromInner};
1415

@@ -833,8 +834,16 @@ impl From<Ipv6Addr> for IpAddr {
833834
#[stable(feature = "rust1", since = "1.0.0")]
834835
impl fmt::Display for Ipv4Addr {
835836
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
837+
const IPV4_BUF_LEN: usize = 15; // Long enough for the longest possible IPv4 address
838+
let mut buf = [0u8; IPV4_BUF_LEN];
839+
let mut buf_slice = &mut buf[..];
836840
let octets = self.octets();
837-
write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3])
841+
// Note: The call to write should never fail, hence the unwrap
842+
write!(buf_slice, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]).unwrap();
843+
let len = IPV4_BUF_LEN - buf_slice.len();
844+
// This unsafe is OK because we know what is being written to the buffer
845+
let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) };
846+
fmt.pad(buf)
838847
}
839848
}
840849

@@ -1495,18 +1504,40 @@ impl Ipv6Addr {
14951504
#[stable(feature = "rust1", since = "1.0.0")]
14961505
impl fmt::Display for Ipv6Addr {
14971506
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1507+
// Note: The calls to write should never fail, hence the unwraps in the function
1508+
// Long enough for the longest possible IPv6: 39
1509+
const IPV6_BUF_LEN: usize = 39;
1510+
let mut buf = [0u8; IPV6_BUF_LEN];
1511+
let mut buf_slice = &mut buf[..];
1512+
14981513
match self.segments() {
14991514
// We need special cases for :: and ::1, otherwise they're formatted
15001515
// as ::0.0.0.[01]
1501-
[0, 0, 0, 0, 0, 0, 0, 0] => write!(fmt, "::"),
1502-
[0, 0, 0, 0, 0, 0, 0, 1] => write!(fmt, "::1"),
1516+
[0, 0, 0, 0, 0, 0, 0, 0] => write!(buf_slice, "::").unwrap(),
1517+
[0, 0, 0, 0, 0, 0, 0, 1] => write!(buf_slice, "::1").unwrap(),
15031518
// Ipv4 Compatible address
15041519
[0, 0, 0, 0, 0, 0, g, h] => {
1505-
write!(fmt, "::{}.{}.{}.{}", (g >> 8) as u8, g as u8, (h >> 8) as u8, h as u8)
1520+
write!(
1521+
buf_slice,
1522+
"::{}.{}.{}.{}",
1523+
(g >> 8) as u8,
1524+
g as u8,
1525+
(h >> 8) as u8,
1526+
h as u8
1527+
)
1528+
.unwrap();
15061529
}
15071530
// Ipv4-Mapped address
15081531
[0, 0, 0, 0, 0, 0xffff, g, h] => {
1509-
write!(fmt, "::ffff:{}.{}.{}.{}", (g >> 8) as u8, g as u8, (h >> 8) as u8, h as u8)
1532+
write!(
1533+
buf_slice,
1534+
"::ffff:{}.{}.{}.{}",
1535+
(g >> 8) as u8,
1536+
g as u8,
1537+
(h >> 8) as u8,
1538+
h as u8
1539+
)
1540+
.unwrap();
15101541
}
15111542
_ => {
15121543
fn find_zero_slice(segments: &[u16; 8]) -> (usize, usize) {
@@ -1539,25 +1570,33 @@ impl fmt::Display for Ipv6Addr {
15391570
let (zeros_at, zeros_len) = find_zero_slice(&self.segments());
15401571

15411572
if zeros_len > 1 {
1542-
fn fmt_subslice(segments: &[u16], fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1573+
fn fmt_subslice(segments: &[u16], buf: &mut &mut [u8]) {
15431574
if !segments.is_empty() {
1544-
write!(fmt, "{:x}", segments[0])?;
1575+
write!(*buf, "{:x}", segments[0]).unwrap();
15451576
for &seg in &segments[1..] {
1546-
write!(fmt, ":{:x}", seg)?;
1577+
write!(*buf, ":{:x}", seg).unwrap();
15471578
}
15481579
}
1549-
Ok(())
15501580
}
15511581

1552-
fmt_subslice(&self.segments()[..zeros_at], fmt)?;
1553-
fmt.write_str("::")?;
1554-
fmt_subslice(&self.segments()[zeros_at + zeros_len..], fmt)
1582+
fmt_subslice(&self.segments()[..zeros_at], &mut buf_slice);
1583+
write!(buf_slice, "::").unwrap();
1584+
fmt_subslice(&self.segments()[zeros_at + zeros_len..], &mut buf_slice);
15551585
} else {
15561586
let &[a, b, c, d, e, f, g, h] = &self.segments();
1557-
write!(fmt, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}", a, b, c, d, e, f, g, h)
1587+
write!(
1588+
buf_slice,
1589+
"{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
1590+
a, b, c, d, e, f, g, h
1591+
)
1592+
.unwrap();
15581593
}
15591594
}
15601595
}
1596+
let len = IPV6_BUF_LEN - buf_slice.len();
1597+
// This is safe because we know exactly what can be in this buffer
1598+
let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) };
1599+
fmt.pad(buf)
15611600
}
15621601
}
15631602

@@ -1896,6 +1935,18 @@ mod tests {
18961935
assert_eq!(None, none);
18971936
}
18981937

1938+
#[test]
1939+
fn ipv4_addr_to_string() {
1940+
// Short address
1941+
assert_eq!(Ipv4Addr::new(1, 1, 1, 1).to_string(), "1.1.1.1");
1942+
// Long address
1943+
assert_eq!(Ipv4Addr::new(127, 127, 127, 127).to_string(), "127.127.127.127");
1944+
1945+
// Test padding
1946+
assert_eq!(&format!("{:16}", Ipv4Addr::new(1, 1, 1, 1)), "1.1.1.1 ");
1947+
assert_eq!(&format!("{:>16}", Ipv4Addr::new(1, 1, 1, 1)), " 1.1.1.1");
1948+
}
1949+
18991950
#[test]
19001951
fn ipv6_addr_to_string() {
19011952
// ipv4-mapped address
@@ -1909,6 +1960,22 @@ mod tests {
19091960
// v6 address with no zero segments
19101961
assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f");
19111962

1963+
// longest possible IPv6 length
1964+
assert_eq!(
1965+
Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888)
1966+
.to_string(),
1967+
"1111:2222:3333:4444:5555:6666:7777:8888"
1968+
);
1969+
// padding
1970+
assert_eq!(
1971+
&format!("{:20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)),
1972+
"1:2:3:4:5:6:7:8 "
1973+
);
1974+
assert_eq!(
1975+
&format!("{:>20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)),
1976+
" 1:2:3:4:5:6:7:8"
1977+
);
1978+
19121979
// reduce a single run of zeros
19131980
assert_eq!(
19141981
"ae::ffff:102:304",

0 commit comments

Comments
 (0)