I need to compile a program for an ARM device. It seems to be failing here, perhaps because of the type difference on ARM?
unsafe { Ok(String::from(try!(CStr::from_ptr(buf.as_ptr() as *const i8).to_str()))) }
The error is:
694 | unsafe { Ok(String::from(try!(CStr::from_ptr(buf.as_ptr() as *const i8).to_str()))) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected u8, found i8
|
= note: expected type `*const u8`
found type `*const i8`
What is the type difference and how do I fix it?
You probably want to use std::os::raw::c_char instead of i8. (Though that may not be the right place to get the type from. libc::c_char seems to exist as well.)
The basic issue is that the char type in C can be signed or unsigned depending on the platform and that is reflected in the foreign function interface. Ideally you'd like to find a way to do the conversion without having to explicitly mention the type.
Related
I have been writing a program in Rust where I encountered an error relating to moving the data of a Shared Reference.
I made some research, but I was unable to find the cause of the error in the program I have written. Here is the simplified version of the program:
enum A {
Won = 1,
}
struct B {
result: A,
}
fn print_game(game: &B) {
println!("{}", game.result as u32);
}
fn main() {
let game: B = B { result: A::Won };
print_game(&game);
}
The above program when compiled, throws the below error:
error[E0507]: cannot move out of `game.result` which is behind a shared reference
--> src/main.rs:10:20
|
10 | println!("{}", game.result as u32);
| ^^^^^^^^^^^ move occurs because `game.result` has type `A`, which does not implement the `Copy` trait
From the error I can infer that the data in game.result is moved, but, I am not sure where it is moved and why it's been moved.
In rust, default behaviour for custom type is 'move' unless you implement Copy trait for the type.
If the value bound to a variable moves, the variable can not be used anymore. Developers new to Rust must get used to it.
Move is attempted in 'game.result as i32' portion of your code. Type casting is also counted as move for value of 'move' type.
I agree with the solution already mentioned above, just add the line
#[derive(Clone, Copy)]
Rust Playground
Traits like Deref, Into, From etc. could also be relevant, but depends...
By 'move' compiler means just transfer of ownership, not the change of data location in memory.
Suppose we have a variable v bound to a 'move' data. In a type casting like 'v as T' the ownership of data is detached from v and the bytes are reinterpreted as type T.
But why is this casting not allowed in your example?
Actual cause of error is that 'game' is a shared reference of type &B and you tried to use it to detach original ownership of data referred by it.
Shared reference can never be used to move referred data or part of it. <<
In this case I think your enum A just needs a #[derive(Clone, Copy)].
Rust Playground Example
Another option would be to refactor the program to only print what is actually needed:
…
fn main() {
let game: B = B { result: A::Won };
print_result(game.result);
}
Playground
I have a piece of code like this:
use std::cell::RefCell;
use std::rc::Rc;
struct A(bool);
impl A {
fn get_ref(&self) -> &Rc<RefCell<bool>> {
&Rc::new(RefCell::new(self.0))
}
fn copy_ref(&self) -> &Rc<RefCell<bool>> {
Rc::clone(self.get_ref())
}
}
fn main() {
let a = A(true);
a.copy_ref();
}
and I received warning complaining about the Rc::clone function not getting a reference:
error[E0308]: mismatched types
--> src/main.rs:12:9
|
12 | Rc::clone(self.get_ref())
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found struct `std::rc::Rc`
|
= note: expected type `&std::rc::Rc<std::cell::RefCell<bool>>`
found type `std::rc::Rc<std::cell::RefCell<bool>>`
I have been working on this all night but I cannot get it to work. The method get_ref is already typed as returning &Rc<RefCell<bool>>, but why would the compiler give the error?
The error is not talking about the argument you put into Arc::clone(), but the whole expression Rc::clone(...) which has a different type (Rc<...>) than the return type of your function (&Rc<...>).
If you were passing a wrong argument to Rc::clone, it would like look this:
--> src/main.rs:13:19
|
13 | Rc::clone(false)
| ^^^^^ expected reference, found bool
|
= note: expected type `&std::rc::Rc<_>`
found type `bool`
So the naive way to fix the type error is to write &Rc::clone(...) instead. Then the last expression of your function has the same type as your function's declared return type. But as you will notice, you will get other errors afterwards.
Let's take a step back to see that your approach is flawed here. For the most important point, please see "Is there any way to return a reference to a variable created in a function?". Spoiler: you really don't want to. So constructs like your get_ref() just don't make sense, as you return a reference to a variable you create inside your function (a variable of type Rc).
In your case the direct solution is probably pretty simple: just remove the reference. Rc<T> is already a pointer/reference type, so there is no need (in general) to have a reference to it.
However, since you are using Rc, you are probably interested in reference counting. So in that case, you probably shouldn't create a new Rc every time the function is called. Otherwise you could end up with a bunch of Rcs with reference count 1, which is not really the point. So instead, your type A should already store an Rc<RefCell<bool>>.
But all I'm doing here is guessing what you actually want to do which is not clear from your question. Maybe you can ask a different question, or add the information to this question, or explain this in the comments.
I have a type defined as follows (by another crate):
trait Bar {
type Baz;
}
struct Foo<B: Bar, T> {
baz: B::Baz,
t: ::std::marker::PhantomData<T>
}
The type parameter T serves to encode some data at compile-time, and no instances of it will ever exist.
I would like to store a number of Foos, all with the same B, but with different Ts, in a Vec. Any time I am adding to or removing from this Vec I will know the proper T for the item in question by other means.
I know I could have a Vec<Box<Any>>, but do not want to incur the overhead of dynamic dispatch here.
I decided to make it a Vec<Foo<B, ()>>, and transmute to the proper type whenever necessary. However, to my surprise, a function like the following is not allowed:
unsafe fn change_t<B: Bar, T, U>(foo: Foo<B, T>) -> Foo<B, U> {
::std::mem::transmute(foo)
}
This gives the following error:
error[E0512]: transmute called with types of different sizes
--> src/main.rs:13:5
|
13 | ::std::mem::transmute(foo)
| ^^^^^^^^^^^^^^^^^^^^^
|
= note: source type: Foo<B, T> (size can vary because of <B as Bar>::Baz)
= note: target type: Foo<B, U> (size can vary because of <B as Bar>::Baz)
I find this very confusing, as both types have the same B, so their B::Bazes must also be the same, and the type T should not affect the type's layout whatsoever. Why is this not allowed?
It's been brought it to my attention that this sort of transmute results in an error even when the type parameter T is not present at all!
trait Bar {
type Baz;
}
struct Foo<B: Bar> {
baz: B::Baz,
}
unsafe fn change_t<B: Bar>(foo: B::Baz) -> B::Baz {
::std::mem::transmute(foo)
}
playground
Bizarrely, it is not possible to translate even between B::Baz and B::Baz. Unless there is some extremely subtle reasoning that makes this unsafe, this seems very much like a compiler bug.
It seems that for transmute size compatibility can't be verified at compile time for generic T values: so you have to use &T references:
unsafe fn change_t<B: Bar>(foo: &B::Baz) -> &B::Baz {
::std::mem::transmute(foo)
}
This related question contains some interesting details about transmuting.
I released the cluFullTransmute crate (GitHub repository) that solves your question, but it requires a nightly compiler. Give it a try.
This simple program:
fn main() {
let b: Box<i32> = Box::new(1);
b.into_raw();
}
Produces this inconvenient error when compiled with Rust 1.12.0:
error: no method named `into_raw` found for type `Box<i32>` in the current scope
--> <anon>:3:7
|
3 | b.into_raw();
| ^^^^^^^^
|
= note: found the following associated functions; to be used as methods, functions must have a `self` parameter
= note: candidate #1 is defined in an impl for the type `Box<_>`
This is because into_raw is not defined to take self as parameter, but instead is defined as:
impl Box<T: ?Sized> {
fn into_raw(b: Box<T>) -> *mut T;
}
This seems inconvenient, and I cannot find a rationale.
So... why?
Because 99.995% of the time (statistic totally made up), you expect method calls to happen to the thing being pointed to, not to the pointer itself. As a result, the "smart pointer" types in Rust generally avoid doing anything to break that expectation. An obvious exception would be something like Rc/Arc implementing Clone directly.
Box implements Deref, which means that all methods that are enclosed by the Box are automatically made available; from the outside, Box<T> and T look and act the same.
If into_raw were a method instead of an associated function, it would shadow any into_raw method on the contained type.
There are other examples of these enhancing associated functions on Rc, such as downgrade or try_unwrap, or on Arc, such as make_mut.
I'm trying to follow the guide, and am compiling the following code:
use std::rand;
fn main() {
println!("Guess the number!");
let secret_number = (rand::random() % 100i) + 1i;
println!("The secret number is: {}", secret_number);
}
However, I get the following error:
➜ guess git:(master) ✗ cargo run
Compiling guess v0.0.1 (file:///home/mkpankov/rust/guide/guess)
/home/mkpankov/rust/guide/guess/src/main.rs:6:26: 6:40 error: the type of this value must be known in this context
/home/mkpankov/rust/guide/guess/src/main.rs:6 let secret_number = (rand::random() % 100i) + 1i;
^~~~~~~~~~~~~~
error: aborting due to previous error
Could not compile `guess`.
To learn more, run the command again with --verbose.
I looked at definition of %, turns out it uses Rem trait. And the trait defines the operator only on same-typed operands.
Now, I use 100i as second operand, and that should be int, according to reference.
So, why can't compiler infer the proper type requested from random(), as the manual suggests? (and my Haskell experience hints it should).
Not fully sure it's a bug, hence the question.
Some additional info:
➜ guess git:(master) ✗ rustc --version
rustc 0.12.0-nightly (63fe80e1f 2014-10-08 23:42:39 +0000)
Runs on Ubuntu 14.04 x64.
Update: I noticed this error is intended to happen (the guide tells the way to fix it later). However, the original question of why can't the compiler infer the type still applies.
Well, the answer why the compiler can't infer the type is simple. This is Rem definition:
pub trait Rem<RHS, Result> {
fn rem(&self, rhs: &RHS) -> Result;
}
Note that it takes two type parameter, RHS and Result. Each trait also has implicit type parameter called Self, which designates the type for which the trait is implemented. This is how Rem implementation for int looks like:
impl Rem<int, int> for int { ... }
So here Self = int, RHS = int and Result = int. But traits are open, that is, you can implement foreign trait for any type you own and you can implement your own trait for any foreign type. No one can prevent you for adding an implementation like this one (Self = X, RHS = int, Result = int):
struct X;
impl Rem<int, int> for X {
fn rem(&self, arg: &int) -> int { *arg }
}
And now rand::random() invocation is ambiguous: should the type checker select rand::random::<X>() or rand::random::<int>()?
Note that in theory the type checker could decide to use the only type which is applicable in this case. However, this would lead to very fragile programs. Suppose that this is the case and the original program compiles normally. In the same module, but in an unrelated part, you use some other type, say, X, which is imported from another library. And then the author of this library suddenly decides that it would be nice if X implemented Rem<int, int>. Because importing a type also imports all trait implementations for that type, then BAM, you program suddenly stops compiling.
It may be fine if it is your program. After all, you can always notice such compilation error and correct it accordingly. However, suppose that this happens not in your program but in a library you depend on. For example, if liby used X from libx, and then libx author decided to add an offending trait implementation for X, then liby suddenly stops compiling and there is nothing you can do. This would mean, for example, that you won't be able to modify library versions easily.