Tracking issue for IP address convenience constructors, added in #44395, modified in https://github.com/rust-lang/rust/pull/52872.
```rust
impl Ipv4Addr {
pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1);
pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0);
pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255);
}
impl Ipv6Addr {
pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
}
Is there any way to implement these as const
ants?
I personally don't like this kind of trivial function.
See also #39819
I’d also like these to be associated const
items instead. This would require at least these APIs to be made const fn
:
Ipv4Addr::new
Ipv6Addr::new
std::net::hton
u32::to_be
u32::swap_bytes
If we’re doing down this road, it seems like many more APIs should also be const fn
s for consistency, which is starting to be out of scope for this issue.
@rust-lang/libs what do you think?
I think I'd prefer these to be associated consts as well. We don't necessarily need to make all of those functions const as well - we can just directly initialize the structures.
Hmm yes, I suppose we could replace the hton
call with two definitions based on target endianness #[cfg]
.
Maybe I'm missing something, but aren't IP addresses independent of endianness? In other words, aren't they [u8; 4]
?
An Ipv4Addr
is a wrapper around the libc in_addr type, which has a u32 field that needs to hold the IP in big endian.
Right. [u8; 4]
would be a fine way to store it in big-endian with cross-platform code, but Because Reasons the internal type is ultimately big-endian u32
.
OK, thanks for explaining! An alternative would be to just transmute()
, but I'm not sure if transmute()
is a const fn
.
I think I’d prefer this over transmute:
```rust
Ipv4Addr {
inner: c::in_addr {
// 127.0.0.1
#[cfg(target_endian = "big")]
s_addr: 0x7F_00_00_01_u32,
#[cfg(target_endian = "little")]
s_addr: 0x01_00_00_7F_u32,
}
}
````
(Either way, with an assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1))
test.)
The libs team discussed this and the consensus was to stabilize this as associated constants (in uppercase: LOCALHOST
and UNSPECIFIED
.)
@rfcbot fcp merge
Team member @SimonSapin has proposed to merge this. The next step is review by the rest of the tagged teams:
No concerns currently listed.
Once a majority of reviewers approve (and none object), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!
See this document for info about what commands tagged team members can give me.
:bell: This is now entering its final comment period, as per the review above. :bell:
I started working on changing this to associated constants, but ran into a bit of a roadblock. in6_addr
has a non-public parameter, so I'm not sure how to construct an instance of it in a const expression. The only ways I can think of resolving that are to add constant in6_addr instances to libc (at least a zeroed out instance that could then use struct update syntax to update), or make the non-public fields public (which may be problematic if they vary across environments).
hmm, actually it looks like the non-public field is just used for alignment. Maybe now that #[repr(align(...))]
is stabilzed the extra field could be removed in favor of #[repr(align(4))]
@tmccombs Maybe add const fn new(…) -> Self
to those in6_addr
structs?
Maybe add const fn new(…) -> Self to those in6_addr structs?
For unix at least, in6_addr comes from the libc crate. Which it looks like has to support older versions of rust. So even when const fn
is stabilized we can't add it there.
Similarly I don't think I can add #[repr(align(4))]
to libc implementations, unless there is a way to use conditional compilation based on whether a feature is stable, or the version of rust, but I don't know how to do that.
The final comment period is now complete.
I just got PR #51171 merged making the compiler intrinsics for endianess conversion (bswap
) a const fn
. As soon as that hits beta, and thus the stage0 compiler, I plan on pushing a PR making swap_bytes
and to_be
const fn
s on all integers. If this gets accepted, the next step is to make Ipv4Addr::new
a const fn
as well. If all of this goes through these special IP addresses can easily be made into associated constants for Ipv4Addr
.
For Ipv6Addr
I don't know yet. It uses mem::zeroed()
which is not a const fn
.
It uses mem::zeroed() which is not a const fn.
And I don't think it can be, unless it is a compiler intrinsic. And the Ipv4Addr is currently doable (although having a const to_be
fn would make it simpler), but the private field for Ipv6Addr is complicated.
I implemented this (and a bit more) in #52872
This should probably not have been closed :see_no_evil: It was me invalidly writing fixes <number>
in my PR moving from functions to associated constants.
Anyway. Now that this is merged, all that should be left is to mark the constants as stable I guess.
Reopening to track stabilization.
I should point out that I also added Ipv4Addr::BROADCAST
in the same PR where I converted them from functions to constants. Commit: https://github.com/rust-lang/rust/pull/52872/commits/7167a065d1f7ae99b617ff17c47796ece6aaf680
BROADCAST
is added under the same feature gate. So probably good to voice your opinions on that if there are any.
I created a PR to stabilize (including BROADCAST) but can change it if that isn't desired.
Most helpful comment
I implemented this (and a bit more) in #52872