Rust: Tracking issue for IP constructors

Created on 15 Sep 2017  Â·  25Comments  Â·  Source: rust-lang/rust

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);
}

B-unstable C-tracking-issue T-libs disposition-merge finished-final-comment-period

Most helpful comment

I implemented this (and a bit more) in #52872

All 25 comments

Is there any way to implement these as constants?

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 fns 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:

  • [x] @Kimundi
  • [x] @SimonSapin
  • [ ] @alexcrichton
  • [x] @aturon
  • [x] @dtolnay
  • [x] @sfackler
  • [x] @withoutboats

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 fns 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.

Was this page helpful?
0 / 5 - 0 ratings