|
7 | 7 | )] |
8 | 8 |
|
9 | 9 | use crate::cmp::Ordering; |
10 | | -use crate::fmt; |
| 10 | +use crate::fmt::{self, Write as FmtWrite}; |
11 | 11 | use crate::hash; |
12 | | -use crate::io::Write; |
| 12 | +use crate::io::Write as IoWrite; |
13 | 13 | use crate::sys::net::netc as c; |
14 | 14 | use crate::sys_common::{AsInner, FromInner}; |
15 | 15 |
|
@@ -1532,102 +1532,100 @@ impl Ipv6Addr { |
1532 | 1532 | } |
1533 | 1533 | } |
1534 | 1534 |
|
| 1535 | +/// Write an Ipv6Addr, conforming to the canonical style described by |
| 1536 | +/// [RFC 5952](https://tools.ietf.org/html/rfc5952). |
1535 | 1537 | #[stable(feature = "rust1", since = "1.0.0")] |
1536 | 1538 | impl fmt::Display for Ipv6Addr { |
1537 | | - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
1538 | | - // Note: The calls to write should never fail, hence the unwraps in the function |
1539 | | - // Long enough for the longest possible IPv6: 39 |
1540 | | - const IPV6_BUF_LEN: usize = 39; |
1541 | | - let mut buf = [0u8; IPV6_BUF_LEN]; |
1542 | | - let mut buf_slice = &mut buf[..]; |
| 1539 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 1540 | + // If there are no alignment requirements, write out the IP address to |
| 1541 | + // f. Otherwise, write it to a local buffer, then use f.pad. |
| 1542 | + if f.precision().is_none() && f.width().is_none() { |
| 1543 | + let segments = self.segments(); |
| 1544 | + |
| 1545 | + // Special case for :: and ::1; otherwise they get written with the |
| 1546 | + // IPv4 formatter |
| 1547 | + if self.is_unspecified() { |
| 1548 | + f.write_str("::") |
| 1549 | + } else if self.is_loopback() { |
| 1550 | + f.write_str("::1") |
| 1551 | + } else if let Some(ipv4) = self.to_ipv4() { |
| 1552 | + match segments[5] { |
| 1553 | + // IPv4 Compatible address |
| 1554 | + 0 => write!(f, "::{}", ipv4), |
| 1555 | + // IPv4 Mapped address |
| 1556 | + 0xffff => write!(f, "::ffff:{}", ipv4), |
| 1557 | + _ => unreachable!(), |
| 1558 | + } |
| 1559 | + } else { |
| 1560 | + #[derive(Copy, Clone, Default)] |
| 1561 | + struct Span { |
| 1562 | + start: usize, |
| 1563 | + len: usize, |
| 1564 | + } |
1543 | 1565 |
|
1544 | | - match self.segments() { |
1545 | | - // We need special cases for :: and ::1, otherwise they're formatted |
1546 | | - // as ::0.0.0.[01] |
1547 | | - [0, 0, 0, 0, 0, 0, 0, 0] => write!(buf_slice, "::").unwrap(), |
1548 | | - [0, 0, 0, 0, 0, 0, 0, 1] => write!(buf_slice, "::1").unwrap(), |
1549 | | - // Ipv4 Compatible address |
1550 | | - [0, 0, 0, 0, 0, 0, g, h] => { |
1551 | | - write!( |
1552 | | - buf_slice, |
1553 | | - "::{}.{}.{}.{}", |
1554 | | - (g >> 8) as u8, |
1555 | | - g as u8, |
1556 | | - (h >> 8) as u8, |
1557 | | - h as u8 |
1558 | | - ) |
1559 | | - .unwrap(); |
1560 | | - } |
1561 | | - // Ipv4-Mapped address |
1562 | | - [0, 0, 0, 0, 0, 0xffff, g, h] => { |
1563 | | - write!( |
1564 | | - buf_slice, |
1565 | | - "::ffff:{}.{}.{}.{}", |
1566 | | - (g >> 8) as u8, |
1567 | | - g as u8, |
1568 | | - (h >> 8) as u8, |
1569 | | - h as u8 |
1570 | | - ) |
1571 | | - .unwrap(); |
1572 | | - } |
1573 | | - _ => { |
1574 | | - fn find_zero_slice(segments: &[u16; 8]) -> (usize, usize) { |
1575 | | - let mut longest_span_len = 0; |
1576 | | - let mut longest_span_at = 0; |
1577 | | - let mut cur_span_len = 0; |
1578 | | - let mut cur_span_at = 0; |
1579 | | - |
1580 | | - for i in 0..8 { |
1581 | | - if segments[i] == 0 { |
1582 | | - if cur_span_len == 0 { |
1583 | | - cur_span_at = i; |
| 1566 | + // Find the inner 0 span |
| 1567 | + let zeroes = { |
| 1568 | + let mut longest = Span::default(); |
| 1569 | + let mut current = Span::default(); |
| 1570 | + |
| 1571 | + for (i, &segment) in segments.iter().enumerate() { |
| 1572 | + if segment == 0 { |
| 1573 | + if current.len == 0 { |
| 1574 | + current.start = i; |
1584 | 1575 | } |
1585 | 1576 |
|
1586 | | - cur_span_len += 1; |
| 1577 | + current.len += 1; |
1587 | 1578 |
|
1588 | | - if cur_span_len > longest_span_len { |
1589 | | - longest_span_len = cur_span_len; |
1590 | | - longest_span_at = cur_span_at; |
| 1579 | + if current.len > longest.len { |
| 1580 | + longest = current; |
1591 | 1581 | } |
1592 | 1582 | } else { |
1593 | | - cur_span_len = 0; |
1594 | | - cur_span_at = 0; |
| 1583 | + current = Span::default(); |
1595 | 1584 | } |
1596 | 1585 | } |
1597 | 1586 |
|
1598 | | - (longest_span_at, longest_span_len) |
1599 | | - } |
1600 | | - |
1601 | | - let (zeros_at, zeros_len) = find_zero_slice(&self.segments()); |
1602 | | - |
1603 | | - if zeros_len > 1 { |
1604 | | - fn fmt_subslice(segments: &[u16], buf: &mut &mut [u8]) { |
1605 | | - if !segments.is_empty() { |
1606 | | - write!(*buf, "{:x}", segments[0]).unwrap(); |
1607 | | - for &seg in &segments[1..] { |
1608 | | - write!(*buf, ":{:x}", seg).unwrap(); |
1609 | | - } |
| 1587 | + longest |
| 1588 | + }; |
| 1589 | + |
| 1590 | + /// Write a colon-separated part of the address |
| 1591 | + #[inline] |
| 1592 | + fn fmt_subslice(f: &mut fmt::Formatter<'_>, chunk: &[u16]) -> fmt::Result { |
| 1593 | + if let Some(first) = chunk.first() { |
| 1594 | + fmt::LowerHex::fmt(first, f)?; |
| 1595 | + for segment in &chunk[1..] { |
| 1596 | + f.write_char(':')?; |
| 1597 | + fmt::LowerHex::fmt(segment, f)?; |
1610 | 1598 | } |
1611 | 1599 | } |
| 1600 | + Ok(()) |
| 1601 | + } |
1612 | 1602 |
|
1613 | | - fmt_subslice(&self.segments()[..zeros_at], &mut buf_slice); |
1614 | | - write!(buf_slice, "::").unwrap(); |
1615 | | - fmt_subslice(&self.segments()[zeros_at + zeros_len..], &mut buf_slice); |
| 1603 | + if zeroes.len > 1 { |
| 1604 | + fmt_subslice(f, &segments[..zeroes.start])?; |
| 1605 | + f.write_str("::")?; |
| 1606 | + fmt_subslice(f, &segments[zeroes.start + zeroes.len..]) |
1616 | 1607 | } else { |
1617 | | - let &[a, b, c, d, e, f, g, h] = &self.segments(); |
1618 | | - write!( |
1619 | | - buf_slice, |
1620 | | - "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}", |
1621 | | - a, b, c, d, e, f, g, h |
1622 | | - ) |
1623 | | - .unwrap(); |
| 1608 | + fmt_subslice(f, &segments) |
1624 | 1609 | } |
1625 | 1610 | } |
| 1611 | + } else { |
| 1612 | + // Slow path: write the address to a local buffer, the use f.pad. |
| 1613 | + // Defined recursively by using the fast path to write to the |
| 1614 | + // buffer. |
| 1615 | + |
| 1616 | + // This is the largest possible size of an IPv6 address |
| 1617 | + const IPV6_BUF_LEN: usize = (4 * 8) + 7; |
| 1618 | + let mut buf = [0u8; IPV6_BUF_LEN]; |
| 1619 | + let mut buf_slice = &mut buf[..]; |
| 1620 | + |
| 1621 | + // Note: This call to write should never fail, so unwrap is okay. |
| 1622 | + write!(buf_slice, "{}", self).unwrap(); |
| 1623 | + let len = IPV6_BUF_LEN - buf_slice.len(); |
| 1624 | + |
| 1625 | + // This is safe because we know exactly what can be in this buffer |
| 1626 | + let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; |
| 1627 | + f.pad(buf) |
1626 | 1628 | } |
1627 | | - let len = IPV6_BUF_LEN - buf_slice.len(); |
1628 | | - // This is safe because we know exactly what can be in this buffer |
1629 | | - let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; |
1630 | | - fmt.pad(buf) |
1631 | 1629 | } |
1632 | 1630 | } |
1633 | 1631 |
|
|
0 commit comments