Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tracking issue for Ipv{4,6}Addr convenience methods #27709

Open
3 of 28 tasks
alexcrichton opened this issue Aug 12, 2015 · 79 comments
Open
3 of 28 tasks

Tracking issue for Ipv{4,6}Addr convenience methods #27709

alexcrichton opened this issue Aug 12, 2015 · 79 comments
Labels
A-io Area: `std::io`, `std::fs`, `std::net` and `std::path` B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC Libs-Tracked Libs issues that are tracked on the team's project board. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@alexcrichton
Copy link
Member

alexcrichton commented Aug 12, 2015

The below is a list of methods left to be stabilized under the ip feature. The path forward today is unclear; if you'd like to push through any method on here the libs team is interested in a PR with links to the associated RFCs or other official documentation. Let us know!





Steps

Subsets of the listed methods can be stabilized, rather than attempting to stabilize everything at once.

Unresolved Questions

From @KodrAus in #76098 (comment):

  • Should we replace the Ipv6Addr::is_unicast_* methods with a Ipv6Addr::unicast_scope method that returns a Ipv6UnicastScope enum (Stabilize the "IP" feature #76098 (comment))?
  • Should we change the behavior of Ipv6Addr::to_ipv4 to ignore deprecated IPv4-compatible addresses, or deprecate the whole method in favor of the more correct Ipv6Addr::to_ipv4_mapped method (Stabilize the "IP" feature #76098 (comment))?
  • Are we ok with Ipv6Addr::is_* methods now properly considering mapped (non-deprecated) IPv4 addresses? I'd personally be comfortable considering the old behavior a bug.
  • Are there any behavioral differences between other language implementations that we should investigate? (Stabilize the "IP" feature #76098 (comment))
@alexcrichton alexcrichton added A-io T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. B-unstable Blocker: Implemented in the nightly compiler and unstable. labels Aug 12, 2015
@aturon
Copy link
Member

aturon commented Nov 3, 2015

I think we should consider this for stabilization in 1.6. Nominating.

@alexcrichton
Copy link
Member Author

🔔 This issue is now entering its cycle-long final comment period for stabilization 🔔

Concretely, we discussed this in the libs meeting and the conclusion was that the boolean accessors are likely ready for stabilization after verifying that they're all the canonical definitions, but the enum-returning variants will likely remain unstable for now.

@alexcrichton alexcrichton added final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. and removed I-nominated labels Nov 5, 2015
@briansmith
Copy link
Contributor

What, exactly, is the "ip feature"? Could you link to the RustDoc(s) of the specific things that are supposed to be reviewed?

@SimonSapin
Copy link
Contributor

I think "ip feature" in this context refers to things annotated with #![unstable(feature = "ip", …)], which require #![feature(ip)] to be used.

@briansmith
Copy link
Contributor

I think "ip feature" in this context refers to things annotated with #![unstable(feature = "ip", …)], which require #![feature(ip)] to be used.

I don't mean to be rude, but that's just a restating my question as the answer. if you want people to actually give feedback on the proposal, it should be easier to understand what the proposal is. In this case, it is pretty difficult to tell what is being proposed because the module mixes stable and unstable features.

I noticed that a large part of this module could work in #![no_std] mode. I suggest moving the #![no_std]-compatible parts to core::net, or at least consider how making it work with #![no_std] would affect the API.

It also seems odd that Ipv4Addr and Ipv6Addr have things like is_multicast and is_global but there's no trait that allows code to make these queries generically over those types of addresses. If such a trait were to bad added later, would the existence of these non-trait methods cause problems? If so, it might be worth considering building the trait first.

@steveklabnik
Copy link
Member

@briansmith I don't think that's being rude, there's just tension here between "we've been doing this a while so we're a bit short" and "newer people might not know what that is." @SimonSapin leaned a bit towards a literal explanation, but you're right to point out that more detail is good.

I read @alexcrichton 's comment as:

that the boolean accessors are likely ready for stabilization after verifying that they're all the canonical definitions,

http://doc.rust-lang.org/std/net/struct.Ipv4Addr.html and http://doc.rust-lang.org/std/net/struct.Ipv6Addr.html <- all the stuff here that is -> bool

but the enum-returning variants will likely remain unstable for now.

http://doc.rust-lang.org/std/net/struct.Ipv6Addr.html#method.multicast_scope is the only one I see that's unstable.

@huonw
Copy link
Member

huonw commented Nov 6, 2015

FWIW, I filed #29221 a while ago, which would make tracking down what these tracking issues refer to slightly easier.

@alexcrichton
Copy link
Member Author

Yes, to be concrete, I was proposing stabilizing:

  • Ipv4Addr::is_unspecified
  • Ipv4Addr::is_loopback
  • Ipv4Addr::is_private
  • Ipv4Addr::is_link_local
  • Ipv4Addr::is_global
  • Ipv4Addr::is_multicast
  • Ipv4Addr::is_broadcast
  • Ipv4Addr::is_documentation
  • Ipv6Addr::is_unspecified
  • Ipv6Addr::is_loopback
  • Ipv6Addr::is_global
  • Ipv6Addr::is_unique_local
  • Ipv6Addr::is_unicast_link_local
  • Ipv6Addr::is_unicast_site_local
  • Ipv6Addr::is_unicast_global
  • Ipv6Addr::is_multicast

Note that this is all pending actually verifying that these are standard properties of the respective IP address space and are well known with canonical implementations. I believe they fit this requirement already but would like to double-check.


@briansmith

I suggest moving the #![no_std]-compatible parts to core::net

Yeah these things can certainly move around over time (it's backwards compatible to move them at a later date). I'd be a little wary of putting things in core "just because" without a concrete purpose, and these kinda fall into the category I'd be wary of. For example the internal representation of each of these primitives is the libc equivalent (e.g. libc::sockaddr_in6 or libc::in_addr) which unfortunately isn't available in libcore, so if we move it to core we'd have to invent our own storage format.

It also seems odd that Ipv4Addr and Ipv6Addr have things like is_multicast and is_global but there's no trait that allows code to make these queries generically over those types of addresses. If such a trait were to bad added later, would the existence of these non-trait methods cause problems?

Method resolution favors inherent methods (methods defined on the type itself) over trait methods (e.g. impl'd traits plus the trait being in scope), so in that sense we're covered to add a trait at a future date. That being said the standard library doesn't have too many traits like this for abstracting between one or two types, so I would personally want to hold off on this extension for now.

A possible alternative, however, could be adding the common set of methods to IpAddr if we end up stabilizing that as well.

@ollie27
Copy link
Member

ollie27 commented Nov 9, 2015

A couple of issues I have noticed with what we have:

  • 0.0.0.0/8, :: and many more ranges shouldn't return true for is_global()
  • Ipv6Addr::is_documentation is missing and should be 2001:db8::/32

On a more general note, might some of these functions need to be updated in the future if new ranges are assigned? How would that be handled?

@alexcrichton
Copy link
Member Author

Ah I unfortunately did not have time to do an audit of these APIs this cycle, so when the libs team talked about this during triage today the conclusion was to punt this to next cycle, I hope to have the time to investigate it then and incorportate @ollie27's suggestions!

@alexcrichton
Copy link
Member Author

🔔 This issue is now yet again entering its final comment period 🔔

Hopefully I get a chance to researching this API this time around!

@alexcrichton
Copy link
Member Author

alexcrichton commented Jan 12, 2016

Better late than never! -- my analysis:

Of the ipv4 properties, there's more listed on wikipedia at least, for example:

  • Current network
  • Shared
  • protocol assignments (and DS-Lite)
  • ipv6 to ipv4 relay
  • benchmark tests
  • reserved

These sound relatively obscure (at least to me) though, so it seems fine that we don't add them just yet. In terms of what we currently have:

  • Ipv4Addr::is_unspecified - appears to be an ipv6 property, not ipv4?
  • Ipv4Addr::is_loopback - ref
  • Ipv4Addr::is_private - ref1, ref2, ref3
  • Ipv4Addr::is_link_local - ref
  • Ipv4Addr::is_global - not found, this is a property, but haven't found exhaustive documentation
  • Ipv4Addr::is_multicast - ref
  • Ipv4Addr::is_broadcast - ref
  • Ipv4Addr::is_documentation - ref1, ref2, ref3

Like with ipv4 we're missing some ipv6 properties (according to RFC 6890):

  • ipv4-ipv6 transit
  • ipv4-mapped (although we have a method to access this, so probably ok)
  • discard only
  • protocol assignments
  • TEREDO (wut?)
  • benchmarking
  • documentation
  • ORCHID
  • 6to4

Of the ipv6 methods:

  • Ipv6Addr::is_unspecified - ref
  • Ipv6Addr::is_loopback - ref
  • Ipv6Addr::is_global - couldn't find a reference online quickly, seems to have some interesting logic though?
  • Ipv6Addr::is_unique_local - ref
  • Ipv6Addr::is_unicast_link_local - ref, called "Linked-Scope Unicast" in the RFC at least, not sure about the name in that case.
  • Ipv6Addr::is_unicast_site_local - didn't find a reference in this RFC at least
  • Ipv6Addr::is_unicast_global - same as above, didn't find a reference (doesn't mean it's wrong though!)
  • Ipv6Addr::is_multicast - ref

From this I'm comfortable stabilizing the checked methods (they've got verified names and implementations at least), but I would personally want some more verification of the unchecked methods before stabilizing.

@vinipsmaker
Copy link

From this I'm comfortable stabilizing the checked methods (they've got verified names and implementations at least), but I would personally want some more verification of the unchecked methods before stabilizing.

Sounds like a good start. The is_loopback would be already useful for me. Having to use only one standard type to represent an ip, no matter whether v4 or v6, would be very useful already.

@alexcrichton
Copy link
Member Author

The libs team discussed this during triage yesterday and the decision was to stabilize the methods I've checked above

alexcrichton added a commit to alexcrichton/rust that referenced this issue Jan 16, 2016
This commit stabilizes and deprecates the FCP (final comment period) APIs for
the upcoming 1.7 beta release. The specific APIs which changed were:

Stabilized

* `Path::strip_prefix` (renamed from `relative_from`)
* `path::StripPrefixError` (new error type returned from `strip_prefix`)
* `Ipv4Addr::is_loopback`
* `Ipv4Addr::is_private`
* `Ipv4Addr::is_link_local`
* `Ipv4Addr::is_multicast`
* `Ipv4Addr::is_broadcast`
* `Ipv4Addr::is_documentation`
* `Ipv6Addr::is_unspecified`
* `Ipv6Addr::is_loopback`
* `Ipv6Addr::is_unique_local`
* `Ipv6Addr::is_multicast`
* `Vec::as_slice`
* `Vec::as_mut_slice`
* `String::as_str`
* `String::as_mut_str`
* `<[T]>::clone_from_slice` - the `usize` return value is removed
* `<[T]>::sort_by_key`
* `i32::checked_rem` (and other signed types)
* `i32::checked_neg` (and other signed types)
* `i32::checked_shl` (and other signed types)
* `i32::checked_shr` (and other signed types)
* `i32::saturating_mul` (and other signed types)
* `i32::overflowing_add` (and other signed types)
* `i32::overflowing_sub` (and other signed types)
* `i32::overflowing_mul` (and other signed types)
* `i32::overflowing_div` (and other signed types)
* `i32::overflowing_rem` (and other signed types)
* `i32::overflowing_neg` (and other signed types)
* `i32::overflowing_shl` (and other signed types)
* `i32::overflowing_shr` (and other signed types)
* `u32::checked_rem` (and other unsigned types)
* `u32::checked_neg` (and other unsigned types)
* `u32::checked_shl` (and other unsigned types)
* `u32::saturating_mul` (and other unsigned types)
* `u32::overflowing_add` (and other unsigned types)
* `u32::overflowing_sub` (and other unsigned types)
* `u32::overflowing_mul` (and other unsigned types)
* `u32::overflowing_div` (and other unsigned types)
* `u32::overflowing_rem` (and other unsigned types)
* `u32::overflowing_neg` (and other unsigned types)
* `u32::overflowing_shl` (and other unsigned types)
* `u32::overflowing_shr` (and other unsigned types)
* `ffi::IntoStringError`
* `CString::into_string`
* `CString::into_bytes`
* `CString::into_bytes_with_nul`
* `From<CString> for Vec<u8>`
* `From<CString> for Vec<u8>`
* `IntoStringError::into_cstring`
* `IntoStringError::utf8_error`
* `Error for IntoStringError`

Deprecated

* `Path::relative_from` - renamed to `strip_prefix`
* `Path::prefix` - use `components().next()` instead
* `os::unix::fs` constants - moved to the `libc` crate
* `fmt::{radix, Radix, RadixFmt}` - not used enough to stabilize
* `IntoCow` - conflicts with `Into` and may come back later
* `i32::{BITS, BYTES}` (and other integers) - not pulling their weight
* `DebugTuple::formatter` - will be removed
* `sync::Semaphore` - not used enough and confused with system semaphores

Closes rust-lang#23284
cc rust-lang#27709 (still lots more methods though)
Closes rust-lang#27712
Closes rust-lang#27722
Closes rust-lang#27728
Closes rust-lang#27735
Closes rust-lang#27729
Closes rust-lang#27755
Closes rust-lang#27782
Closes rust-lang#27798
workingjubilee pushed a commit to tcdi/postgrestd that referenced this issue Sep 15, 2022
Stabilize `Ipv6Addr::to_ipv4_mapped`

CC rust-lang/rust#27709 (tracking issue for the `ip` feature which contains more
functions)

The function `Ipv6Addr::to_ipv4` is bad because it also returns an IPv4
address for the IPv6 loopback address `::1`. Stabilize
`Ipv6Addr::to_ipv4_mapped` so we can recommend that function instead.
chrysn added a commit to chrysn/portcontrolcd that referenced this issue Apr 14, 2023
This avoids the otherwise confusing errors in the shape of

> Error binding socket to [fe80::...]:0: Invalid argument (os error 22)

Code for this was already in place but pending on is_unicast_link_local
stabilization. As this has not happened in several years, a manual
workaround (with the same note to wait for stabilization) is chosen.

Workaround-For: rust-lang/rust#27709
@tcoratger
Copy link

Regarding the is_global function applied to ipv4 and ipv6 addresses here, when looking at the IANA standard, I realized that there are several addresses considered as Special-Purpose Address which are not listed in the std is_global condition. Is this normal?

Despite the fact that some of the addresses in the IANA table are considered globally reachable, it is notified at the beginning of the document:

Address prefixes listed in the Special-Purpose Address Registry are not guaranteed routability in any particular local or global context.

So in my view all addresses in the IANA table should be considered in the condition as not being is_global, is there something I've misunderstood here?

tgross35 added a commit to tgross35/rust that referenced this issue Sep 19, 2023
Make `IpAddr::to_canonical` and `IpV6Addr::to_canonical` stable, as well as
const stabilize `Ipv6Addr::to_ipv4_mapped`.

Newly stable API:

    impl IpAddr {
        // Now stable under `ip_to_canonical`
        const fn to_canonical(&self) -> IpAddr;
    }

    impl Ipv6Addr {
        // Now stable under `ip_to_canonical`
        const fn to_canonical(&self) -> IpAddr;

        // Already stable, this makes it const stable under
        // `const_ipv6_to_ipv4_mapped
        const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr>
    }

These stabilize a subset of the following tracking issues:

- rust-lang#27709
- rust-lang#76205
tgross35 added a commit to tgross35/rust that referenced this issue Sep 19, 2023
Make `IpAddr::to_canonical` and `IpV6Addr::to_canonical` stable, as well as
const stabilize `Ipv6Addr::to_ipv4_mapped`.

Newly stable API:

    impl IpAddr {
        // Now stable under `ip_to_canonical`
        const fn to_canonical(&self) -> IpAddr;
    }

    impl Ipv6Addr {
        // Now stable under `ip_to_canonical`
        const fn to_canonical(&self) -> IpAddr;

        // Already stable, this makes it const stable under
        // `const_ipv6_to_ipv4_mapped`
        const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr>
    }

These stabilize a subset of the following tracking issues:

- rust-lang#27709
- rust-lang#76205
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Oct 15, 2023
Stabilize `{IpAddr, Ipv6Addr}::to_canonical`

Make `IpAddr::to_canonical` and `IpV6Addr::to_canonical` stable (+const), as well as const stabilize `Ipv6Addr::to_ipv4_mapped`.

Newly stable API:

```rust
impl IpAddr {
    // Newly stable under `ip_to_canonical`
    const fn to_canonical(&self) -> IpAddr;
}

impl Ipv6Addr {
    // Newly stable under `ip_to_canonical`
    const fn to_canonical(&self) -> IpAddr;

    // Already stable, this makes it const stable under
    // `const_ipv6_to_ipv4_mapped`
    const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr>
}
```

These stabilize a subset of the following tracking issues:

- rust-lang#27709
- rust-lang#76205

Stabilization of all methods under the `ip` gate was attempted once at rust-lang#66584 then again at rust-lang#76098. These were not successful because there are still unknowns about `is_documentation` `is_benchmarking` and similar; `to_canonical` is much more straightforward.

I have looked and could not find any known issues with `to_canonical`. These were added in 2021 in rust-lang#87708

cc implementor `@the8472`

r? libs-api
`@rustbot` label +T-libs-api +needs-fcp
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Oct 16, 2023
Stabilize `{IpAddr, Ipv6Addr}::to_canonical`

Make `IpAddr::to_canonical` and `IpV6Addr::to_canonical` stable (+const), as well as const stabilize `Ipv6Addr::to_ipv4_mapped`.

Newly stable API:

```rust
impl IpAddr {
    // Newly stable under `ip_to_canonical`
    const fn to_canonical(&self) -> IpAddr;
}

impl Ipv6Addr {
    // Newly stable under `ip_to_canonical`
    const fn to_canonical(&self) -> IpAddr;

    // Already stable, this makes it const stable under
    // `const_ipv6_to_ipv4_mapped`
    const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr>
}
```

These stabilize a subset of the following tracking issues:

- rust-lang#27709
- rust-lang#76205

Stabilization of all methods under the `ip` gate was attempted once at rust-lang#66584 then again at rust-lang#76098. These were not successful because there are still unknowns about `is_documentation` `is_benchmarking` and similar; `to_canonical` is much more straightforward.

I have looked and could not find any known issues with `to_canonical`. These were added in 2021 in rust-lang#87708

cc implementor ``@the8472``

r? libs-api
``@rustbot`` label +T-libs-api +needs-fcp
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Oct 16, 2023
Rollup merge of rust-lang#115955 - tgross35:ip-to-canonical, r=dtolnay

Stabilize `{IpAddr, Ipv6Addr}::to_canonical`

Make `IpAddr::to_canonical` and `IpV6Addr::to_canonical` stable (+const), as well as const stabilize `Ipv6Addr::to_ipv4_mapped`.

Newly stable API:

```rust
impl IpAddr {
    // Newly stable under `ip_to_canonical`
    const fn to_canonical(&self) -> IpAddr;
}

impl Ipv6Addr {
    // Newly stable under `ip_to_canonical`
    const fn to_canonical(&self) -> IpAddr;

    // Already stable, this makes it const stable under
    // `const_ipv6_to_ipv4_mapped`
    const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr>
}
```

These stabilize a subset of the following tracking issues:

- rust-lang#27709
- rust-lang#76205

Stabilization of all methods under the `ip` gate was attempted once at rust-lang#66584 then again at rust-lang#76098. These were not successful because there are still unknowns about `is_documentation` `is_benchmarking` and similar; `to_canonical` is much more straightforward.

I have looked and could not find any known issues with `to_canonical`. These were added in 2021 in rust-lang#87708

cc implementor ``@the8472``

r? libs-api
``@rustbot`` label +T-libs-api +needs-fcp
@jstasiak
Copy link
Contributor

Hi everyone,

The following concerns mostly is_global and a little bit is_unicast_global.

I took the ipcheck tool[1] (which gave us some very useful data two years ago[2]) and modified it slightly to:

  • Extend the range of addresses tested[3]
  • Use the current Rust implementation as the baseline[4]
  • Optionally compare against multiple Python versions (because I've been working on the Python side of things as well)
  • Only include the differences on the is_global front as the rest didn't interest me

I present you two tables. The content is collapsed because of its length, you'll have to click on the arrows to see everything.

Table 1. The status quo as of today (Rust nightly, Python versions as specified, Go 1.21.5)
addr Python 3.8 Python 3.9 Python 3.10 Python 3.11 Python 3.12 Go
0.0.0.0 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
0.1.2.3 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
1.1.1.1 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
127.0.0.1 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
255.255.255.255 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
10.0.0.1 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
16.89.10.65 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
45.22.13.197 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
100.64.0.0 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
100.128.0.0 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
169.254.0.0 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
172.16.10.10 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
192.0.0.0 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
192.0.0.7 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
192.0.0.8 { is_global : false (Rust) ≠ true (Python 3.8) } { is_global : false (Rust) ≠ true (Python 3.9) } { is_global : false (Rust) ≠ true (Python 3.10) } { is_global : false (Rust) ≠ true (Python 3.11) } { is_global : false (Rust) ≠ true (Python 3.12) } { is_global : false (Rust) ≠ true (Go) }
192.0.0.9 { is_global : false (Rust) ≠ true (Python 3.8) } { is_global : false (Rust) ≠ true (Python 3.9) } { is_global : false (Rust) ≠ true (Python 3.10) } { is_global : false (Rust) ≠ true (Python 3.11) } { is_global : false (Rust) ≠ true (Python 3.12) } { is_global : false (Rust) ≠ true (Go) }
192.0.0.10 { is_global : false (Rust) ≠ true (Python 3.8) } { is_global : false (Rust) ≠ true (Python 3.9) } { is_global : false (Rust) ≠ true (Python 3.10) } { is_global : false (Rust) ≠ true (Python 3.11) } { is_global : false (Rust) ≠ true (Python 3.12) } { is_global : false (Rust) ≠ true (Go) }
192.0.0.169 { is_global : false (Rust) ≠ true (Python 3.8) } { is_global : false (Rust) ≠ true (Python 3.9) } { is_global : false (Rust) ≠ true (Python 3.10) } { is_global : false (Rust) ≠ true (Python 3.11) } { is_global : false (Rust) ≠ true (Python 3.12) } { is_global : false (Rust) ≠ true (Go) }
192.0.0.170 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
192.0.0.171 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
192.0.0.172 { is_global : false (Rust) ≠ true (Python 3.8) } { is_global : false (Rust) ≠ true (Python 3.9) } { is_global : false (Rust) ≠ true (Python 3.10) } { is_global : false (Rust) ≠ true (Python 3.11) } { is_global : false (Rust) ≠ true (Python 3.12) } { is_global : false (Rust) ≠ true (Go) }
192.0.0.255 { is_global : false (Rust) ≠ true (Python 3.8) } { is_global : false (Rust) ≠ true (Python 3.9) } { is_global : false (Rust) ≠ true (Python 3.10) } { is_global : false (Rust) ≠ true (Python 3.11) } { is_global : false (Rust) ≠ true (Python 3.12) } { is_global : false (Rust) ≠ true (Go) }
192.0.2.2 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
192.31.196.2 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
192.52.193.2 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
192.88.99.2 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
192.168.0.2 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
192.175.48.2 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
198.18.0.0 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
198.51.100.2 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
203.0.113.6 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
240.0.0.0 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
255.255.255.254 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:0.0.0.0 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
::ffff:0.1.2.3 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:1.1.1.1 ✔️ ✔️ { is_global : false (Rust) ≠ true (Python 3.10) } { is_global : false (Rust) ≠ true (Python 3.11) } { is_global : false (Rust) ≠ true (Python 3.12) } { is_global : false (Rust) ≠ true (Go) }
::ffff:127.0.0.1 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
::ffff:255.255.255.255 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
::ffff:10.0.0.1 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:16.89.10.65 ✔️ ✔️ { is_global : false (Rust) ≠ true (Python 3.10) } { is_global : false (Rust) ≠ true (Python 3.11) } { is_global : false (Rust) ≠ true (Python 3.12) } { is_global : false (Rust) ≠ true (Go) }
::ffff:45.22.13.197 ✔️ ✔️ { is_global : false (Rust) ≠ true (Python 3.10) } { is_global : false (Rust) ≠ true (Python 3.11) } { is_global : false (Rust) ≠ true (Python 3.12) } { is_global : false (Rust) ≠ true (Go) }
::ffff:100.64.0.0 ✔️ ✔️ { is_global : false (Rust) ≠ true (Python 3.10) } { is_global : false (Rust) ≠ true (Python 3.11) } { is_global : false (Rust) ≠ true (Python 3.12) } { is_global : false (Rust) ≠ true (Go) }
::ffff:100.128.0.0 ✔️ ✔️ { is_global : false (Rust) ≠ true (Python 3.10) } { is_global : false (Rust) ≠ true (Python 3.11) } { is_global : false (Rust) ≠ true (Python 3.12) } { is_global : false (Rust) ≠ true (Go) }
::ffff:169.254.0.0 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
::ffff:172.16.10.10 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:192.0.0.0 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:192.0.0.7 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:192.0.0.8 ✔️ ✔️ { is_global : false (Rust) ≠ true (Python 3.10) } { is_global : false (Rust) ≠ true (Python 3.11) } { is_global : false (Rust) ≠ true (Python 3.12) } { is_global : false (Rust) ≠ true (Go) }
::ffff:192.0.0.9 ✔️ ✔️ { is_global : false (Rust) ≠ true (Python 3.10) } { is_global : false (Rust) ≠ true (Python 3.11) } { is_global : false (Rust) ≠ true (Python 3.12) } { is_global : false (Rust) ≠ true (Go) }
::ffff:192.0.0.10 ✔️ ✔️ { is_global : false (Rust) ≠ true (Python 3.10) } { is_global : false (Rust) ≠ true (Python 3.11) } { is_global : false (Rust) ≠ true (Python 3.12) } { is_global : false (Rust) ≠ true (Go) }
::ffff:192.0.0.169 ✔️ ✔️ { is_global : false (Rust) ≠ true (Python 3.10) } { is_global : false (Rust) ≠ true (Python 3.11) } { is_global : false (Rust) ≠ true (Python 3.12) } { is_global : false (Rust) ≠ true (Go) }
::ffff:192.0.0.170 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:192.0.0.171 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:192.0.0.172 ✔️ ✔️ { is_global : false (Rust) ≠ true (Python 3.10) } { is_global : false (Rust) ≠ true (Python 3.11) } { is_global : false (Rust) ≠ true (Python 3.12) } { is_global : false (Rust) ≠ true (Go) }
::ffff:192.0.0.255 ✔️ ✔️ { is_global : false (Rust) ≠ true (Python 3.10) } { is_global : false (Rust) ≠ true (Python 3.11) } { is_global : false (Rust) ≠ true (Python 3.12) } { is_global : false (Rust) ≠ true (Go) }
::ffff:192.0.2.2 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:192.31.196.2 ✔️ ✔️ { is_global : false (Rust) ≠ true (Python 3.10) } { is_global : false (Rust) ≠ true (Python 3.11) } { is_global : false (Rust) ≠ true (Python 3.12) } { is_global : false (Rust) ≠ true (Go) }
::ffff:192.52.193.2 ✔️ ✔️ { is_global : false (Rust) ≠ true (Python 3.10) } { is_global : false (Rust) ≠ true (Python 3.11) } { is_global : false (Rust) ≠ true (Python 3.12) } { is_global : false (Rust) ≠ true (Go) }
::ffff:192.88.99.2 ✔️ ✔️ { is_global : false (Rust) ≠ true (Python 3.10) } { is_global : false (Rust) ≠ true (Python 3.11) } { is_global : false (Rust) ≠ true (Python 3.12) } { is_global : false (Rust) ≠ true (Go) }
::ffff:192.168.0.2 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:192.175.48.2 ✔️ ✔️ { is_global : false (Rust) ≠ true (Python 3.10) } { is_global : false (Rust) ≠ true (Python 3.11) } { is_global : false (Rust) ≠ true (Python 3.12) } { is_global : false (Rust) ≠ true (Go) }
::ffff:198.18.0.0 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:198.51.100.2 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:203.0.113.6 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:240.0.0.0 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:255.255.255.254 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
::1 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
:: ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
64:ff9b:: ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
64:ff9b:1:: { is_global : false (Rust) ≠ true (Python 3.8) } { is_global : false (Rust) ≠ true (Python 3.9) } { is_global : false (Rust) ≠ true (Python 3.10) } { is_global : false (Rust) ≠ true (Python 3.11) } { is_global : false (Rust) ≠ true (Python 3.12) } { is_global : false (Rust) ≠ true (Go) }
100:: ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
2001:: ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
2001:1::1 { is_global : true (Rust) ≠ false (Python 3.8) } { is_global : true (Rust) ≠ false (Python 3.9) } { is_global : true (Rust) ≠ false (Python 3.10) } { is_global : true (Rust) ≠ false (Python 3.11) } { is_global : true (Rust) ≠ false (Python 3.12) } ✔️
2001:1::2 { is_global : true (Rust) ≠ false (Python 3.8) } { is_global : true (Rust) ≠ false (Python 3.9) } { is_global : true (Rust) ≠ false (Python 3.10) } { is_global : true (Rust) ≠ false (Python 3.11) } { is_global : true (Rust) ≠ false (Python 3.12) } ✔️
2001:2:: ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
2001:0002:6c::430 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
2001:3:: { is_global : true (Rust) ≠ false (Python 3.8) } { is_global : true (Rust) ≠ false (Python 3.9) } { is_global : true (Rust) ≠ false (Python 3.10) } { is_global : true (Rust) ≠ false (Python 3.11) } { is_global : true (Rust) ≠ false (Python 3.12) } ✔️
2001:4:112:: { is_global : true (Rust) ≠ false (Python 3.8) } { is_global : true (Rust) ≠ false (Python 3.9) } { is_global : true (Rust) ≠ false (Python 3.10) } { is_global : true (Rust) ≠ false (Python 3.11) } { is_global : true (Rust) ≠ false (Python 3.12) } ✔️
2001:10:: ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
2001:10:240:ab::a ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
2001:20:: { is_global : true (Rust) ≠ false (Python 3.8) } { is_global : true (Rust) ≠ false (Python 3.9) } { is_global : true (Rust) ≠ false (Python 3.10) } { is_global : true (Rust) ≠ false (Python 3.11) } { is_global : true (Rust) ≠ false (Python 3.12) } ✔️
2001:30:: ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
2001:db8:8:4::2 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
2002:: ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
2002:cb0a:3cdd:1::1 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
2620:4f:8000:: ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
fdf8:f53b:82e4::53 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : false (Rust) ≠ true (Go) }
fe80::200:5aee:feaa:20a2 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
ff01:0:0:0:0:0:0:2 ✔️ ✔️ ✔️ ✔️ ✔️ { is_global : true (Rust) ≠ false (Go) }
Table 2. Patched Rust, patched CPython, regular Go.
addr Python Go
0.0.0.0 ✔️ ✔️
0.1.2.3 ✔️ { is_global : false (Rust) ≠ true (Go) }
1.1.1.1 ✔️ ✔️
127.0.0.1 ✔️ ✔️
255.255.255.255 ✔️ ✔️
10.0.0.1 ✔️ { is_global : false (Rust) ≠ true (Go) }
16.89.10.65 ✔️ ✔️
45.22.13.197 ✔️ ✔️
100.64.0.0 ✔️ { is_global : false (Rust) ≠ true (Go) }
100.128.0.0 ✔️ ✔️
169.254.0.0 ✔️ ✔️
172.16.10.10 ✔️ { is_global : false (Rust) ≠ true (Go) }
192.0.0.0 ✔️ { is_global : false (Rust) ≠ true (Go) }
192.0.0.7 ✔️ { is_global : false (Rust) ≠ true (Go) }
192.0.0.8 ✔️ { is_global : false (Rust) ≠ true (Go) }
192.0.0.9 ✔️ ✔️
192.0.0.10 ✔️ ✔️
192.0.0.169 ✔️ { is_global : false (Rust) ≠ true (Go) }
192.0.0.170 ✔️ { is_global : false (Rust) ≠ true (Go) }
192.0.0.171 ✔️ { is_global : false (Rust) ≠ true (Go) }
192.0.0.172 ✔️ { is_global : false (Rust) ≠ true (Go) }
192.0.0.255 ✔️ { is_global : false (Rust) ≠ true (Go) }
192.0.2.2 ✔️ { is_global : false (Rust) ≠ true (Go) }
192.31.196.2 ✔️ ✔️
192.52.193.2 ✔️ ✔️
192.88.99.2 ✔️ ✔️
192.168.0.2 ✔️ { is_global : false (Rust) ≠ true (Go) }
192.175.48.2 ✔️ ✔️
198.18.0.0 ✔️ { is_global : false (Rust) ≠ true (Go) }
198.51.100.2 ✔️ { is_global : false (Rust) ≠ true (Go) }
203.0.113.6 ✔️ { is_global : false (Rust) ≠ true (Go) }
240.0.0.0 ✔️ { is_global : false (Rust) ≠ true (Go) }
255.255.255.254 ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:0.0.0.0 ✔️ ✔️
::ffff:0.1.2.3 ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:1.1.1.1 { is_global : false (Rust) ≠ true (Python) } { is_global : false (Rust) ≠ true (Go) }
::ffff:127.0.0.1 ✔️ ✔️
::ffff:255.255.255.255 ✔️ ✔️
::ffff:10.0.0.1 ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:16.89.10.65 { is_global : false (Rust) ≠ true (Python) } { is_global : false (Rust) ≠ true (Go) }
::ffff:45.22.13.197 { is_global : false (Rust) ≠ true (Python) } { is_global : false (Rust) ≠ true (Go) }
::ffff:100.64.0.0 { is_global : false (Rust) ≠ true (Python) } { is_global : false (Rust) ≠ true (Go) }
::ffff:100.128.0.0 { is_global : false (Rust) ≠ true (Python) } { is_global : false (Rust) ≠ true (Go) }
::ffff:169.254.0.0 ✔️ ✔️
::ffff:172.16.10.10 ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:192.0.0.0 ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:192.0.0.7 ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:192.0.0.8 ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:192.0.0.9 { is_global : false (Rust) ≠ true (Python) } { is_global : false (Rust) ≠ true (Go) }
::ffff:192.0.0.10 { is_global : false (Rust) ≠ true (Python) } { is_global : false (Rust) ≠ true (Go) }
::ffff:192.0.0.169 ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:192.0.0.170 ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:192.0.0.171 ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:192.0.0.172 ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:192.0.0.255 ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:192.0.2.2 ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:192.31.196.2 { is_global : false (Rust) ≠ true (Python) } { is_global : false (Rust) ≠ true (Go) }
::ffff:192.52.193.2 { is_global : false (Rust) ≠ true (Python) } { is_global : false (Rust) ≠ true (Go) }
::ffff:192.88.99.2 { is_global : false (Rust) ≠ true (Python) } { is_global : false (Rust) ≠ true (Go) }
::ffff:192.168.0.2 ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:192.175.48.2 { is_global : false (Rust) ≠ true (Python) } { is_global : false (Rust) ≠ true (Go) }
::ffff:198.18.0.0 ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:198.51.100.2 ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:203.0.113.6 ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:240.0.0.0 ✔️ { is_global : false (Rust) ≠ true (Go) }
::ffff:255.255.255.254 ✔️ { is_global : false (Rust) ≠ true (Go) }
::1 ✔️ ✔️
:: ✔️ ✔️
64:ff9b:: ✔️ ✔️
64:ff9b:1:: ✔️ { is_global : false (Rust) ≠ true (Go) }
100:: ✔️ { is_global : false (Rust) ≠ true (Go) }
2001:: ✔️ { is_global : false (Rust) ≠ true (Go) }
2001:1::1 ✔️ ✔️
2001:1::2 ✔️ ✔️
2001:2:: ✔️ { is_global : false (Rust) ≠ true (Go) }
2001:0002:6c::430 ✔️ { is_global : false (Rust) ≠ true (Go) }
2001:3:: ✔️ ✔️
2001:4:112:: ✔️ ✔️
2001:10:: ✔️ { is_global : false (Rust) ≠ true (Go) }
2001:10:240:ab::a ✔️ { is_global : false (Rust) ≠ true (Go) }
2001:20:: ✔️ ✔️
2001:30:: ✔️ ✔️
2001:db8:8:4::2 ✔️ { is_global : false (Rust) ≠ true (Go) }
2002:: ✔️ { is_global : false (Rust) ≠ true (Go) }
2002:cb0a:3cdd:1::1 ✔️ { is_global : false (Rust) ≠ true (Go) }
2620:4f:8000:: ✔️ ✔️
fdf8:f53b:82e4::53 ✔️ { is_global : false (Rust) ≠ true (Go) }
fe80::200:5aee:feaa:20a2 ✔️ ✔️
ff01:0:0:0:0:0:0:2 ✔️ { is_global : true (Rust) ≠ false (Go) }

In table 1 you'll see some Rust/Python disagreement in the following ranges: 192.0.0.0/24, 64:ff9b:1::/48, 2001::/23.

You'll also notice that starting with version 3.10 Python started to interpret IPv4-mapped IPv6 addresses as their IPv4 counterparts for the purposes of evaluating is_global – it's not important to my message but I thought I'd mention it. I'm not particularly fond of that.

I consider both Rust and Python implementations somewhat buggy, sometimes buggy in the same way (for example when it comes to the 2002::/16 range).

In table 2 we have Rust/Python/Go comparison where

With the patches in place Rust and Python are in almost perfect agreement on the is_global front – the only exception is handling of the IPv4-mapped IPv6 addresses. I believe it's a direction worth pursuing.

With the Rust patch the number of Rust/Go disagreements decreases by 1 (I think) but the nature of the disagreements changes (in both ways, it's roughly equalized).

The implementation I propose is consistent with what's proposed by @tcoratger above (#27709 (comment)).

The tables don't capture the difference in is_unicast_global behavior as ipcheck doesn't test that.

[1] https://github.com/rust-lang/libs-team/tree/main/tools/ipcheck
[2] #76098 (comment)
[3] rust-lang/libs-team#317
[4] rust-lang/libs-team#318

@emhane
Copy link

emhane commented May 20, 2024

looking forward to stabilisation of Ipv4Addr::is_reserved!

could theses simple convenience methods be included? possibly also on SocketAddr

impl IpAddr {
    pub fn ipv4(&self) -> Option<&Ipv4Addr> {
        match self {
            IpAddr::V4(ip) => Some(ip),
            IpAddr::V6(_) => None,
        }
    }

    pub fn ipv6(&self) -> Option<&Ipv6Addr> {
        match self {
            IpAddr::V4(_) => None,
            IpAddr::V6(ip) => Some(ip),
        }
    }
}

matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Oct 13, 2024
core/net: add Ipv[46]Addr::from_octets, Ipv6Addr::from_segments.

Adds:

- `Ipv4Address::from_octets([u8;4])`
- `Ipv6Address::from_octets([u8;16])`
- `Ipv6Address::from_segments([u16;8])`

equivalent to the existing `From` impls.

Advantages:

- Consistent with `to_bits, from_bits`.
- More discoverable than the `From` impls.
- Helps with type inference: it's common to want to convert byte slices to IP addrs. If you try this

```rust
fn foo(x: &[u8]) -> Ipv4Addr {
   Ipv4Addr::from(foo.try_into().unwrap())
}
```

it [doesn't work](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=0e2873312de275a58fa6e33d1b213bec). You have to write `Ipv4Addr::from(<[u8;4]>::try_from(x).unwrap())` instead, which is not great. With `from_octets` it is able to infer the right types.

Found this while porting [smoltcp](https://github.com/smoltcp-rs/smoltcp/) from its own IP address types to the `core::net` types.

~~Tracking issues rust-lang#27709 rust-lang#76205~~
Tracking issue: rust-lang#131360
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Oct 14, 2024
core/net: add Ipv[46]Addr::from_octets, Ipv6Addr::from_segments.

Adds:

- `Ipv4Address::from_octets([u8;4])`
- `Ipv6Address::from_octets([u8;16])`
- `Ipv6Address::from_segments([u16;8])`

equivalent to the existing `From` impls.

Advantages:

- Consistent with `to_bits, from_bits`.
- More discoverable than the `From` impls.
- Helps with type inference: it's common to want to convert byte slices to IP addrs. If you try this

```rust
fn foo(x: &[u8]) -> Ipv4Addr {
   Ipv4Addr::from(foo.try_into().unwrap())
}
```

it [doesn't work](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=0e2873312de275a58fa6e33d1b213bec). You have to write `Ipv4Addr::from(<[u8;4]>::try_from(x).unwrap())` instead, which is not great. With `from_octets` it is able to infer the right types.

Found this while porting [smoltcp](https://github.com/smoltcp-rs/smoltcp/) from its own IP address types to the `core::net` types.

~~Tracking issues rust-lang#27709 rust-lang#76205~~
Tracking issue: rust-lang#131360
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Oct 14, 2024
Rollup merge of rust-lang#130629 - Dirbaio:net-from-octets, r=tgross35

core/net: add Ipv[46]Addr::from_octets, Ipv6Addr::from_segments.

Adds:

- `Ipv4Address::from_octets([u8;4])`
- `Ipv6Address::from_octets([u8;16])`
- `Ipv6Address::from_segments([u16;8])`

equivalent to the existing `From` impls.

Advantages:

- Consistent with `to_bits, from_bits`.
- More discoverable than the `From` impls.
- Helps with type inference: it's common to want to convert byte slices to IP addrs. If you try this

```rust
fn foo(x: &[u8]) -> Ipv4Addr {
   Ipv4Addr::from(foo.try_into().unwrap())
}
```

it [doesn't work](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=0e2873312de275a58fa6e33d1b213bec). You have to write `Ipv4Addr::from(<[u8;4]>::try_from(x).unwrap())` instead, which is not great. With `from_octets` it is able to infer the right types.

Found this while porting [smoltcp](https://github.com/smoltcp-rs/smoltcp/) from its own IP address types to the `core::net` types.

~~Tracking issues rust-lang#27709 rust-lang#76205~~
Tracking issue: rust-lang#131360
compiler-errors added a commit to compiler-errors/rust that referenced this issue Nov 22, 2024
…ocal, r=dtolnay

Stabilize `Ipv6Addr::is_unique_local` and `Ipv6Addr::is_unicast_link_local`

Make `Ipv6Addr::is_unique_local` and `Ipv6Addr::is_unicast_link_local` stable (+const).

Newly stable API:

```rust
impl Ipv6Addr {
	// Newly stable under `ipv6_is_unique_local`
	const fn is_unique_local(&self) -> bool;

	// Newly stable under `ipv6_is_unique_local`
	const fn is_unicast_link_local(&self) -> bool;
}
```

These stabilise a subset of the following tracking issue:
- rust-lang#27709

I have looked and could not find any issues with `is_unique_local` and `is_unicast_link_local`. There is a well received comment calling for stabilisation of the latter function.

Both functions are well defined and consistent with implementations in other languages:
- [Go](https://cs.opensource.google/go/go/+/refs/tags/go1.23.0:src/net/netip/netip.go;l=518)
- [Python](https://github.com/python/cpython/blob/e9d1bf353c3ccafc0d9b61b1b3688051bc976604/Lib/ipaddress.py#L2319-L2321)
- [Ruby (unique local)](https://ruby-doc.org/stdlib-2.5.1/libdoc/ipaddr/rdoc/IPAddr.html#private-3F-source)
- [Ruby (unicast link local)](https://ruby-doc.org/stdlib-2.5.1/libdoc/ipaddr/rdoc/IPAddr.html#link_local-3F-source)

cc implementor `@little-dude`
(I can't find the original PR for `is_unqiue_local`)

r? libs-api
`@rustbot` label +T-libs-api +needs-fcp
bors added a commit to rust-lang-ci/rust that referenced this issue Nov 22, 2024
…al, r=dtolnay

Stabilize `Ipv6Addr::is_unique_local` and `Ipv6Addr::is_unicast_link_local`

Make `Ipv6Addr::is_unique_local` and `Ipv6Addr::is_unicast_link_local` stable (+const).

Newly stable API:

```rust
impl Ipv6Addr {
	// Newly stable under `ipv6_is_unique_local`
	const fn is_unique_local(&self) -> bool;

	// Newly stable under `ipv6_is_unique_local`
	const fn is_unicast_link_local(&self) -> bool;
}
```

These stabilise a subset of the following tracking issue:
- rust-lang#27709

I have looked and could not find any issues with `is_unique_local` and `is_unicast_link_local`. There is a well received comment calling for stabilisation of the latter function.

Both functions are well defined and consistent with implementations in other languages:
- [Go](https://cs.opensource.google/go/go/+/refs/tags/go1.23.0:src/net/netip/netip.go;l=518)
- [Python](https://github.com/python/cpython/blob/e9d1bf353c3ccafc0d9b61b1b3688051bc976604/Lib/ipaddress.py#L2319-L2321)
- [Ruby (unique local)](https://ruby-doc.org/stdlib-2.5.1/libdoc/ipaddr/rdoc/IPAddr.html#private-3F-source)
- [Ruby (unicast link local)](https://ruby-doc.org/stdlib-2.5.1/libdoc/ipaddr/rdoc/IPAddr.html#link_local-3F-source)

cc implementor `@little-dude`
(I can't find the original PR for `is_unqiue_local`)

r? libs-api
`@rustbot` label +T-libs-api +needs-fcp
bors added a commit to rust-lang-ci/rust that referenced this issue Nov 22, 2024
…al, r=dtolnay

Stabilize `Ipv6Addr::is_unique_local` and `Ipv6Addr::is_unicast_link_local`

Make `Ipv6Addr::is_unique_local` and `Ipv6Addr::is_unicast_link_local` stable (+const).

Newly stable API:

```rust
impl Ipv6Addr {
	// Newly stable under `ipv6_is_unique_local`
	const fn is_unique_local(&self) -> bool;

	// Newly stable under `ipv6_is_unique_local`
	const fn is_unicast_link_local(&self) -> bool;
}
```

These stabilise a subset of the following tracking issue:
- rust-lang#27709

I have looked and could not find any issues with `is_unique_local` and `is_unicast_link_local`. There is a well received comment calling for stabilisation of the latter function.

Both functions are well defined and consistent with implementations in other languages:
- [Go](https://cs.opensource.google/go/go/+/refs/tags/go1.23.0:src/net/netip/netip.go;l=518)
- [Python](https://github.com/python/cpython/blob/e9d1bf353c3ccafc0d9b61b1b3688051bc976604/Lib/ipaddress.py#L2319-L2321)
- [Ruby (unique local)](https://ruby-doc.org/stdlib-2.5.1/libdoc/ipaddr/rdoc/IPAddr.html#private-3F-source)
- [Ruby (unicast link local)](https://ruby-doc.org/stdlib-2.5.1/libdoc/ipaddr/rdoc/IPAddr.html#link_local-3F-source)

cc implementor `@little-dude`
(I can't find the original PR for `is_unqiue_local`)

r? libs-api
`@rustbot` label +T-libs-api +needs-fcp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-io Area: `std::io`, `std::fs`, `std::net` and `std::path` B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC Libs-Tracked Libs issues that are tracked on the team's project board. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.