Using unstable APIs? Tell us about it!

position_elem from SliceExt.

Would it be possible to get a more specific error message about what unstable element is being used?

Let us take the latest IntoIterator changes.

let vs = vec![1, 2, 3, 4];
for v in vs {
    println!("{}", v);
}

gives

main.rs:4:5: 7:2 warning: use of unstable library feature 'core'
main.rs:4     for v in vs {
main.rs:5         println!("{}", v);
main.rs:6     }
main.rs:7 }
main.rs:4:5: 7:2 help: add #![feature(core)] to the crate attributes to silence this warning
main.rs:4     for v in vs {
main.rs:5         println!("{}", v);
main.rs:6     }
main.rs:7 }

From this it is very hard to find out what is actually being used.
It would be very convenient if it mentioned what is the cause of this.

1 Like

Usually it’s much more clear than that. In this case, I think the problem is that the referenced item (IntoIterator) is only implicitly in the desugared version of the code.

More commonly you’re just calling some unstable method, in which case the error span is more precise.

rust-url uses:

  • In the core feature: into_owned, Cow, Error trait, from_str_radix
  • In the collections feature: char_at, char_range_at, position_elem
  • In the std_misc feature: is_ascii, into_ascii_lowercase, to_ascii_lowercase

I also have a lot of as_slice and some range, but these have a replacement. Maybe they should be deprecated rather than unstable now?

In my project that deals a lot with ffi, I use:

  • std::slice::from_raw_buf
  • std::ffi::c_str_to_bytes
  • std::ffi::CString
  • std::marker::ContravariantLifetime
  • std::string::String::from_str
    • could be replaced with to_string, but it’s apparently more performant
  • std::ptr::PtrExt::as_ref
    • it’s a really nice convenience, but I could live without it
  • std::vec::Vec::map_in_place
    • doubt it’ll be stabilized and I could transmute instead

Note though that this particular warning is very easy to hit and very confusing. I was just surprised by it in the playpen and it took me a little while to pare my program down and then find this thread and @wahrsagevogel’s post about the same issue. It’s pretty jarring to get a confusing warning from pretty much the simplest possible post-hello-world program.

This thread seems like a rather adhoc approach to this, and I’m not sure its useful.

Wouldn’t it be significantly easier and more meaningful to grep crates.io for #[feature] tags, and look at what people are actually using?

The ‘give feedback’ can then be; publish your crate on crates.io and make sure it compiles.

(Obviously you’d have to filter out old crates which are broken, but that’s something crates.io needs to do anyway)

(or search github for rust projects and do the same)

This approach will be workable in the long run, once we’ve split up the feature names at a finer grain. Right now, though, knowing that a crate uses “core” or “collections” isn’t so informative – it’s helpful to know the specific APIs, and the use cases motivating them.

dbus-rs uses:
from core: IntoCow, Str, Error
from alloc: Weak
from std_misc: CString, c_str_to_bytes
from libc: mostly basic stuff like c_void, c_int, c_char, etc

Not all code that uses unstable APIs is on crates.io. Not all use of current use of rust is open source.

3 Likes

I also am depending a lot on the unstable unboxed_closures feature (using the Fn* traits w/ angle bracket notation).

As far as I know, the Fn traits can’t be stabilized yet because the final syntax will likely use variadic generics.

I’m using a few unstable APIs from collections for &strs in a lexer I’m writing:

  • char_at
  • contains_char
  • find_str

The warning messages imply that these will either be renamed or a more generic version will be offered, so I’m not too worried.

collections:
String::from_str

std_msc:
as_raw_fd
CString
c_str_to_bytes

core:
range

libc:
c_void, c_int, etc...
consts::os::extra::O_NONBLOCK
consts::os::posix01::F_SETFL

The ability to get a raw fd and set flags so that system calls can be used to read/write to sockets is especially useful if the core io lib wants to be used, and achieve non-blocking io on *nix systems.

I’m working on a Rust plugin for NetBeans that embeds the Rust compiler in Java via JNI. The main things that are important to me are:

  • libc / std_misc features: FFI stuff for fields on structs that pass between Java and Rust

    • c_int, c_char, CString::from_slice, ffi::c_str_to_bytes
  • unwind::try (from std_misc)

    • because the lexer and parser both panic when they come across fatal errors, which will bring down the JVM. Instead of returning values from the parser or lexer, I pass them back to Java in a callback in the try block. I think I wouldn’t need this API if the compiler API returned errors instead of panicking.
  • rustc_private feature. I use the compiler, parser and lexer APIs in the following crates:

    • rustc (mostly to create a session before compiling)
    • rustc_driver (to run about half of what rustc does, in order to get compile errors for highlighting)
    • rustc_trans (only for one line: there was a slight limitation with the rustc_driver API that made me dig deeper)
    • sytnax (for the lexer, parser and visitor APIs, to get parse errors and for syntax highlighting)

range is replaced by the (..) notation, e.g. range(0, 5) is now (0..5).

std::num::Int::{zero, one, count_ones}

These are useful for generic integer algorithms. It looks like all of the generic casting functions/methods are still unstable.

Could you tell me about your use of allocate/deallocate, and whether you could work around it? These are going to be tricky to stabilize for 1.0

You can see the full code for yourself, but the general idea is that I have an interned string pool. The pool itself maintains a list of Chunks, which are just areas of bytes where I stick a bunch of strings. It’s entirely possible that I could just replace the backing memory with a Vec<u8> with a capacity. It would be a bit slower as I think the chunk would need to be initialized to zero though, and the whole point was to eke out maximum speed. :smile:

Vecs don’t need to be initialized to 0, you could always do:

let mut v: Vec<u8> = Vec::with_capacity(cap);
unsafe { v.set_len(cap); }

And then you’ve got a buffer without having to initialize its contents.