|
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