ipv4_display/
lib.rs

1#![doc = include_str!("../README.md")]
2
3#[cfg(feature = "ufmt")]
4#[doc(hidden)]
5pub mod ufmt;
6
7use std::{fmt, net::Ipv4Addr, str};
8
9const MAX_LEN: usize = 3 * 4 + 3;
10type Buf = [u8; MAX_LEN];
11
12macro_rules! write_octet {
13    ($octet:expr, $buf:ident, $at:ident) => {
14        let octet = $octet;
15        if octet >= 100 {
16            $buf[$at] = b'0' + octet / 100;
17            $at += 1;
18        }
19        if octet >= 10 {
20            $buf[$at] = b'0' + (octet / 10) % 10;
21            $at += 1;
22        }
23        $buf[$at] = b'0' + octet % 10;
24        $at += 1;
25    };
26}
27
28const fn ipv4_display(ip: Ipv4Addr) -> (Buf, usize) {
29    let mut arr: Buf = [b'.'; MAX_LEN];
30    let mut at = 0;
31
32    let [a, b, c, d] = ip.octets();
33    write_octet!(a, arr, at);
34    at += 1;
35    write_octet!(b, arr, at);
36    at += 1;
37    write_octet!(c, arr, at);
38    at += 1;
39    write_octet!(d, arr, at);
40
41    (arr, at)
42}
43
44#[repr(transparent)]
45#[derive(Clone, Copy)]
46/// A wrapper around [`Ipv4Addr`], providing an implementation of [`fmt::Display`]
47/// that is more performant than the one provided by the Rust standard library.
48///
49/// Examples:
50/// ```rust
51/// use std::net::Ipv4Addr;
52/// use ipv4_display::Ipv4AddrDisplay;
53///
54/// assert_eq!(Ipv4AddrDisplay::new(Ipv4Addr::UNSPECIFIED).to_string(), "0.0.0.0");
55/// assert_eq!(Ipv4AddrDisplay::new(Ipv4Addr::LOCALHOST).to_string(), "127.0.0.1");
56/// assert_eq!(Ipv4AddrDisplay::new(Ipv4Addr::new(231, 2, 30, 102)).to_string(), "231.2.30.102");
57/// ```
58pub struct Ipv4AddrDisplay(Ipv4Addr);
59
60impl Ipv4AddrDisplay {
61    #[inline]
62    pub fn new(addr: Ipv4Addr) -> Self {
63        Self(addr)
64    }
65}
66
67impl From<Ipv4Addr> for Ipv4AddrDisplay {
68    #[inline]
69    fn from(addr: Ipv4Addr) -> Self {
70        Self(addr)
71    }
72}
73
74impl fmt::Display for Ipv4AddrDisplay {
75    #[inline]
76    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
77        let (arr, len) = ipv4_display(self.0);
78        f.write_str(unsafe { str::from_utf8_unchecked(&arr[..len]) })
79    }
80}
81
82impl fmt::Debug for Ipv4AddrDisplay {
83    #[inline]
84    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85        fmt::Display::fmt(self, f)
86    }
87}