Unresolved import `core::array::FixedSizeArray` - rust

I am new to Rust.
I've been given some Rust code to work with but the cargo build fails with error "unresolved import core::array::FixedSizeArray". In what way can I remove the error?
I'm using version 1.57.0 nightly; do not know which version of Rust the code base has been build successfully last time.
The code also uses a lot of '#![feature(...)]', which could not be used with stable version. How do I map a feature in older version's nightly build to the current version's functions/etc.?
Example of features:
#![feature(vec_resize_default)]
#![feature(fixed_size_array)]
Thanks.

The last version with FixedSizeArray was the 1.52.1 release. It was designed for generically working with fixed size arrays [T; N] in contexts where &[T] or AsRef<[T]> were not appropriate. But even in the tracking issue it is known that its usefulness was limited and would eventually be overshadowed by min_const_generics which was just made stable in the 1.51.0 release.
You will have to either downgrade your nightly version back to 1.52.1 or before, or fix the problems caused by its removal. There is no way to just use removed features on a newer version.
Some options for replacing this functionality:
It can be translated directly into the form [T; N] using const generics.
struct MyStruct<A: FixedSizeArray> {
data: A
}
fn make_my_struct<A: FixedSizeArray>(data: A) -> MyStruct<A> {
MyStruct { data }
}
Would become:
struct MyStruct<T, const N: usize> {
data: [T; N]
}
fn make_my_struct<T, const N: usize>(data: [T; N]) -> MyStruct<T, N> {
MyStruct { data }
}
Perhaps you didn't need it in the first place and can get by with just &[T] or AsRef<[T]>.
Use a trait from a crate that has a similar purpose like Array from the array_ext crate.
Make your own trait. FixedSizeArray doesn't require any compiler magic, but to implement it for all array types you'd have to use method #1 above anyway.

I "translated" a trait bound using FixedSizeArray like so:
old:
U: FixedSizeArray<T>
new:
U: AsRef<[T]> + AsMut<[T]>>

Related

Rust Generics, "`T` may not live long enough"

I'm trying to imbed Lua into Rust using Mlua. Using its guided tour, I successfully loaded and evaluated a chunk of Lua code. My next goal is to combine this with opening a file and reading its contents. This is where things get problematic:
use anyhow::Result;
use mlua::{Lua, UserData};
use std::fs;
pub struct LuaManager {
lua_state: Lua
}
impl LuaManager {
pub fn new() -> Self {
LuaManager {
lua_state: Lua::new(),
}
}
pub fn eval<T>(&self, chunk: &str) -> Result<T> where T: Clone + UserData {
let v = self.lua_state.load(chunk).eval::<T>()?;
Ok(v)
}
}
Since scripts can return literally anything, I thought a trait-locked generic annotation would solve the issue: The problem is this:
Error generated by rustc: the parameter type `T` may not live long enough... so that the type `T` will meet its required lifetime bounds...
For reference, here is the function signature as defined in lua.rs:
pub fn eval<R: FromLuaMulti<'lua>>(self) -> Result<R>
I don't understand why I'm having this issue. I've looked this up and this question pertained to user-created types, which to my knowledge I'm not doing... so what is the problem here? It's clear that things like <i32> won't die anytime soon. Cargo did suggest adding a static lifetime annotation, but doing some research into it points me to trying to solve the problem without using it first, since in 99% of cases you actually can get away without it.
Unfortunately in this case it seems like 'static is really required.
Lua::load() takes &'lua self and returns Chunk<'lua, '_>. Chunk::<'lua, '_>::eval::<R>() requires R: FromLuaMulti<'lua>. FromLuaMulti<'lua> is implemented for T: FromLua<'lua>. FromLua<'lua> is implemented for T: UserData, however it requires T: 'static (and also T: Clone, but this is irrelevant).

Why does switching from struct to enum breaks API, exactly?

I encountered an interesting change in a public PR.
Initially they had:
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
pub struct ParseError(ParseErrorKind);
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
enum ParseErrorKind {
OutOfRange // ... omitting other values here to be short
}
ParseError cannot be instantiated by clients because ParseErrorKind is private. They are making that enum public now, which seems ok, but I suggested an alternative: have ParseError be an enum itself, and leverage the type system instead of imitating it with the notion of "kind". They told me that would be an API breakage, and therefore was not ok.
I think I understand why in theory a struct and an enum are different. But I am not sure to understand why it is incompatible in this precise case.
Since the struct ParseError had no mutable field and cannot be instantiated by clients, there was nothing we could do with the type but to assign it and compare it. It seems both struct and enum support that, so client code is unlikely to require a change to compile with a newer version exposing an enum instead of struct. Or did I miss another use we could have with the struct, that would result in requiring a change in client code?
However there might be an ABI incompatibility too. How does Rust handle the struct in practice, knowing that only the library can construct it? Is there any sort of allocation or deallocation mechanism that requires to know precisely what ParseError is made of at buildtime? And does switching from that exact struct to an enum impact that? Or could it be safe in this particular case? And is that relevant to try to maintain the ABI since it is not guaranteed so far?
That's because every struct has fields, and hence this pattern will work for any struct, but will not compile with an enum:
struct Foo {}
fn returns_a_foo() -> Foo {
// anything that may return a Foo
}
if let Foo { .. } = returns_a_foo() {}
For example, this code compiles:
fn main() {
if let String { .. } = String::new() {}
}
Playground.
And while probably not code you'd write on your own, it's still possible to write, and additionally, possible to generate through a macro. Note that this is then, obviously, not compatible with an enum pattern match:
if let Option { .. } = None {
// Compile error.
}
Playground.

Why is the trait not implemented?

I wanted to try the amethyst_physics library to make a game. (Duh)
I followed to Example, but somhow I does not work:
use amethyst::GameDataBuilder;
use amethyst_physics::{PhysicsBundle};
use amethyst_nphysics::NPhysicsBackend;
fn main() -> amethyst::Result<()> {
amethyst::start_logger(Default::default());
let game_data = GameDataBuilder::default()
.with_bundle(
PhysicsBundle::<f32, NPhysicsBackend>::new()
)
;
Ok(())
}
Error:
the trait bound `amethyst_physics::PhysicsBundle<'_, '_, f32, amethyst_nphysics::NPhysicsBackend>: amethyst::amethyst_core::SystemBundle<'_, '_>` is not satisfied
the trait `amethyst::amethyst_core::SystemBundle<'_, '_>` is not implemented for `amethyst_physics::PhysicsBundle<'_, '_, f32, amethyst_nphysics::NPhysicsBackend>`
Here is the example.
What am I doing wrong?
This appears to be a bug. It compiles successfully using amethyst version 0.15.1 but not 0.15.3. A regression like this is not expected during a patch change.
amethyst uses amethyst_core version 0.15.3 (where SystemBundle is defined) but amethyst_physics uses amethyst_core version 0.10.1.
I've filed an issue on the amethyst repository.
Use this as a workaround:
amethyst = { version = ">=0.15.0, <0.15.3", features = ["empty"] }

Why doesn't String implement From<&String>?

Background
I know that in Rust people prefer &str rather than &String. But in some case we were only given &String.
One example is when you call std::iter::Iterator::peekable. The return value is a Peekable<I> object that wraps the original iterator into it and gives you one extra method peek.
The point here is that peek only gives you a reference to the iterator item. So if you have an iterator that contains Strings, you only have &String in this case. Of cause, you can easily use as_str to get a &str but in the code I will show below it is equivalent to a call to clone.
The question
This code
#[derive(Debug)]
struct MyStruct(String);
impl MyStruct {
fn new<T>(t: T) -> MyStruct
where
T: Into<String>,
{
MyStruct(t.into())
}
}
fn main() {
let s: String = "Hello world!".into();
let st: MyStruct = MyStruct::new(&s);
println!("{:?}", st);
}
doesn't compile because String doesn't implement From<&String>. This is not intuitive.
Why does this not work? Is it just a missing feature of the standard library or there are some other reasons that prevent the standard library from implementing it?
In the real code, I only have a reference to a String and I know to make it work I only need to call clone instead, but I want to know why.
To solve your problem, one could imagine adding a new generic impl to the standard library:
impl<'a, T: Clone> From<&'a T> for T { ... }
Or to make it more generic:
impl<B, O> From<B> for O where B: ToOwned<Owned=O> { ... }
However, there are two problems with doing that:
Specialization: the specialization feature that allows to overlapping trait-impls is still unstable. It turns out that designing specialization in a sound way is way more difficult than expected (mostly due to lifetimes).
Without it being stable, the Rust devs are very careful not to expose that feature somewhere in the standard library's public API. This doesn't mean that it isn't used at all in std! A famous example is the specialized ToString impl for str. It was introduced in this PR. As you can read in the PR's discussion, they only accepted it because it does not change the API (to_string() was already implemented for str).
However, it's different when we would add the generic impl above: it would change the API. Thus, it's not allowed in std yet.
core vs std: the traits From and Into are defined in the
core library, whereas Clone and ToOwned are defined in std. This means that we can't add a generic impl in core, because core doesn't know anything about std. But we also can't add the generic impl in std, because generic impls need to be in the same crate as the trait (it's a consequence of the orphan rules).
Thus, it would required some form of refactoring and moving around definitions (which may or may not be difficult) before able to add such a generic impl.
Note that adding
impl<'a> From<&'a String> for String { ... }
... works just fine. It doesn't require specialization and doesn't have problems with orphan rules. But of course, we wouldn't want to add a specific impl, when the generic impl would make sense.
(thanks to the lovely people on IRC for explaining stuff to me)
Since String does implement From<&str>, you can make a simple change:
fn main() {
let s: String = "Hello world!".into();
// Replace &s with s.as_str()
let st: MyStruct = MyStruct::new(s.as_str());
println!("{:?}", st);
}
All &Strings can be trivially converted into &str via as_str, which is why all APIs should prefer to use &str; it's a strict superset of accepting &String.

Why is Vec::resize an unstable function?

As stated in the documentation Vec has to be stable in 1.0-beta. However, if I try to call resize I see the following error message:
error: use of unstable library feature 'collections': matches collection reform specification; waiting for dust to settle
It can be easily reproduced, e.g. here: http://is.gd/IhEfEu
fn main() {
let mut v = vec![1, 2, 3, 4];
v.resize(10, 0);
}
A function can be marked as unstable, and Vec::resize is:
The yellow bar on the left indicates stability, and hovering over it describes why it is unstable.
I think it is an issue in the documentation.
The stable attribute can be applied to the crate, to the type or to individual functions, but in the documentation you cannot see the deprecation status of functions, only of types and crates.
If you go to the source, you will see:
impl<T: Clone> Vec<T> {
/// ...
#[unstable(feature = "collections",
reason = "matches collection reform specification; waiting for dust to settle")]
pub fn resize(&mut self, new_len: usize, value: T) {
And, as you can see in this file, there are still a lot of unstable functions in this module.

Resources