Embedded Rust Discovery Book example fails to compile - rust

I am new to rust and embedded systems. I was reading and going along "The Discovery Book" and I can't seem to figure out the errors below.
I have placed this in my main.rs:
#![deny(unsafe_code)]
#![no_main]
#![no_std]
use aux5::{entry, prelude::*, Delay, Leds};
#[entry]
fn main() -> ! {
let (mut delay, mut leds): (Delay, Leds) = aux5::init();
let half_period = 500_u16;
loop {
leds[0].on();
delay.delay_ms(half_period);
leds[0].off();
delay.delay_ms(half_period);
}
}
My auxiliary lib.rs contains:
pub use stm32f3_discovery::{leds::Leds, stm32f3xx_hal, switch_hal};
pub use switch_hal::{ActiveHigh, OutputSwitch, Switch, ToggleableOutputSwitch};
use stm32f3xx_hal::prelude::*;
pub use stm32f3xx_hal::{
delay::Delay,
gpio::{gpioe, Output, PushPull},
hal::blocking::delay::DelayMs,
stm32,
};
pub type LedArray = [Switch<gpioe::PEx<Output<PushPull>>, ActiveHigh>; 8];
pub fn init() -> (Delay, LedArray) {
let device_periphs = stm32::Peripherals::take().unwrap();
let mut reset_and_clock_control = device_periphs.RCC.constrain();
let core_periphs = cortex_m::Peripherals::take().unwrap();
let mut flash = device_periphs.FLASH.constrain();
let clocks = reset_and_clock_control.cfgr.freeze(&mut flash.acr);
let delay = Delay::new(core_periphs.SYST, clocks);
// initialize user leds
let mut gpioe = device_periphs.GPIOE.split(&mut reset_and_clock_control.ahb);
let leds = Leds::new(
gpioe.pe8,
gpioe.pe9,
gpioe.pe10,
gpioe.pe11,
gpioe.pe12,
gpioe.pe13,
gpioe.pe14,
gpioe.pe15,
&mut gpioe.moder,
&mut gpioe.otyper,
);
(delay, leds.into_array())
}
I have not changed anything in lib.rs and I am following the instructions from the book, along with the source code.
Running the code results in the following errors when building for the target:
error[E0432]: unresolved import `aux5::prelude`
--> src\05-led-roulette\src\main.rs:5:19
|
5 | use aux5::{entry, prelude::*, Delay, Leds};
| ^^^^^^^ could not find `prelude` in `aux5`
error[E0308]: mismatched types
--> src\05-led-roulette\src\main.rs:9:48
|
9 | let (mut delay, mut leds): (Delay, Leds) = aux5::init();
| ------------- ^^^^^^^^^^^^ expected struct `Leds`, found array of 8 elements
| |
| expected due to this
|
= note: expected tuple `(Delay, Leds)`
found tuple `(Delay, [Switch<PEx<Output<PushPull>>, ActiveHigh>; 8])`
error[E0608]: cannot index into a value of type `Leds`
--> src\05-led-roulette\src\main.rs:14:9
|
14 | leds[0].on();
| ^^^^^^^
error[E0599]: no method named `delay_ms` found for struct `Delay` in the current scope
--> src\05-led-roulette\src\main.rs:15:15
|
15 | delay.delay_ms(half_period);
| ^^^^^^^^ method not found in `Delay`
|
= help: items from traits can only be used if the trait is in scope
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
|
5 | use aux5::DelayMs;
|
error[E0608]: cannot index into a value of type `Leds`
--> src\05-led-roulette\src\main.rs:17:9
|
17 | leds[0].off();
| ^^^^^^^
error[E0599]: no method named `delay_ms` found for struct `Delay` in the current scope
--> src\05-led-roulette\src\main.rs:18:15
|
18 | delay.delay_ms(half_period);
| ^^^^^^^^ method not found in `Delay`
|
= help: items from traits can only be used if the trait is in scope
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
|
5 | use aux5::DelayMs;
|
error: aborting due to 6 previous errors
Some errors have detailed explanations: E0308, E0432, E0599, E0608.
For more information about an error, try `rustc --explain E0308`.
error: could not compile `led-roulette`
To learn more, run the command again with --verbose.

From the following page, "The Led and Delay abstractions", it looks like this is the set of imports that you need.
use aux5::{entry, Delay, DelayMs, LedArray, OutputSwitch};
In the above abstraction, compared to your main.rs, note the:
Addition of DelayMs trait, making .delay_ms() available.
Removal of a prelude as it is not being used.
Change from Leds to the expected LedArray.
Also see:
Stack Overflow, "Why do I need to import a trait to use the methods it defines for a type?"

Related

implementing obj-rs example to glium

I am trying to load a model into glium, I am using crate obj-rs for this. My model works fine with this example. Unfortunately whenever I try to move code from the example to my project (which is basically code copied from here) I fail with an error:
error[E0277]: the trait bound `glium::Display: glium::backend::Facade` is not satisfied
--> src/main.rs:27:32
|
27 | let vb = obj.vertex_buffer(&display)?;
| ------------- ^^^^^^^^ the trait `glium::backend::Facade` is not implemented for `glium::Display`
| |
| required by a bound introduced by this call
|
= help: the trait `glium::backend::Facade` is implemented for `Rc<glium::context::Context>`
note: required by a bound in `obj::glium_support::<impl Obj<V, I>>::vertex_buffer`
--> /Users/user/project/obj-rs/src/lib.rs:309:33
|
309 | pub fn vertex_buffer<F: Facade>(
| ^^^^^^ required by this bound in `obj::glium_support::<impl Obj<V, I>>::vertex_buffer`
error[E0277]: the trait bound `glium::Display: glium::backend::Facade` is not satisfied
--> src/main.rs:28:31
|
28 | let ib = obj.index_buffer(&display)?;
| ------------ ^^^^^^^^ the trait `glium::backend::Facade` is not implemented for `glium::Display`
| |
| required by a bound introduced by this call
|
= help: the trait `glium::backend::Facade` is implemented for `Rc<glium::context::Context>`
note: required by a bound in `obj::glium_support::<impl Obj<V, I>>::index_buffer`
--> /Users/user/project/obj-rs/src/lib.rs:317:32
|
317 | pub fn index_buffer<F: Facade>(
| ^^^^^^ required by this bound in `obj::glium_support::<impl Obj<V, I>>::index_buffer`
I am new to rust so most of the time I don't know what I am doing. I find it really hard to simply make copied code work. I tried implementing Facade for Display but that didn't seem to make any difference, just more errors. Could you tell me what's wrong, or at least provide me with an example that works, I just want to add my own models to glium examples.
Here are the parts of code that I changed:
fn main() -> Result<(), Box<dyn std::error::Error>>{
#[allow(unused_imports)]
use glium::{glutin, Surface};
use obj::{load_obj, Obj};
use glium::glutin::dpi::LogicalSize;
let event_loop = glutin::event_loop::EventLoop::new();
let window = glutin::window::WindowBuilder::new()
.with_inner_size(LogicalSize::new(500.0, 400.0))
.with_title("obj-rs");
let context = glutin::ContextBuilder::new().with_depth_buffer(24);
let display = glium::Display::new(window, context, &event_loop)?;
let input = include_bytes!("model.obj");
let obj: Obj = load_obj(&input[..])?;
//two lines causing the problem
//let vb = obj.vertex_buffer(&display)?;
//let ib = obj.index_buffer(&display)?;
let positions = glium::VertexBuffer::new(&display, &teapot::VERTICES).unwrap();
..... rest is the same as in the glium example
One thing that I would like to differ from obj-rs example is not to use local source if you know what I mean. Basically something like this:
[dependencies]
glium = "*"
obj-rs = { version = "*", features = ["glium"] }

Rust / Yew Geolocation

I'm trying to retrieve the user's lat/lon, once, in the create function of a Yew Component, so that I can do some math and pass useful decisions to child components. I've made the Yew hook "use_geolocation()" work just fine, but that only runs in a function_component, and there doesn't appear to be any straightforward way to use that location in other components.
Then I found this neat tutorial which uses wasm_bindgen and Seed::app::orders::Orders to make a "cheap clone" of the app, and to call the Javascript functions. The bindings look like:
#[wasm_bindgen]
extern "C" {
type GeolocationCoordinates;
#[wasm_bindgen(method, getter)]
fn latitude(this: &GeolocationCoordinates) -> f64;
#[wasm_bindgen(method, getter)]
fn longitude(this: &GeolocationCoordinates) -> f64;
type GeolocationPosition;
#[wasm_bindgen(method, getter)]
fn coords(this: &GeolocationPosition) ->
GeolocationCoordinates;
}
And the function for fetching geolocation, splicing together the chunks of code from Tor Hovland's tutorial:
let (app, msg_mapper) = (orders.clone_app(), orders.msg_mapper());
let geo_callback = move |position: JsValue| {
let pos: GeolocationPosition = position.into();
let coords = pos.coords();
app.update(msg_mapper(Msg::Position(
coords.latitude(),
coords.longitude(),
)));
};
let geolocation = web_sys::window()
.expect("Unable to get browser window.")
.navigator()
.geolocation()
.expect("Unable to get geolocation.");
let geo_callback_function =
Closure::wrap(
Box::new(|pos| geo_callback(pos)) as Box<dyn Fn(JsValue)>
);
geolocation.get_current_position(
&geo_callback_function.as_ref().unchecked_ref()
).expect("Unable to get position");
geo_callback_function.forget();
I attempted this route, but found that adding the line seed = "0.9.1" into my Cargo.toml produced compile errors, something about a type mismatch between a closure in wasm_bindgen and something in seed. Included here for completeness:
error[E0283]: type annotations needed for `Closure<T>`
--> /home/djmcmath/.cargo/registry/src/github.com-1ecc6299db9ec823/seed-
0.9.1/src/browser/service/routing.rs:87:9
|
87 | let closure = Closure::new(move |event: web_sys::Event| {
| ^^^^^^^
|
= note: cannot satisfy `_: WasmClosure`
note: required by a bound in `Closure::<T>::new`
--> /home/djmcmath/.cargo/registry/src/github.com-1ecc6299db9ec823/wasm-bindgen-
0.2.81/src/closure.rs:251:17
|
251 | T: ?Sized + WasmClosure,
| ^^^^^^^^^^^ required by this bound in `Closure::<T>::new`
help: consider giving `closure` an explicit type, where the type for type parameter
`T` is specified
|
87 | let closure: Closure<T> = Closure::new(move |event: web_sys::Event| {
| ++++++++++++
help: consider specifying the type argument in the function call
|
87 | let closure = Closure::new::<F>(move |event: web_sys::Event| {
| +++++
After beating my head against that brick wall for a while, I decided to just not use Seed, but I don't know of another way to make a "cheap clone" of the app to make the lifetimes work out correctly. Without that, I get the predictable lifetime error on the geo_callback_function:
let geo_callback_function =
Closure::wrap(
Box::new(|pos: JsValue| geo_callback(pos)) as Box<dyn Fn(JsValue)>
);
Error message:
error[E0597]: `geo_callback` does not live long enough
--> src/ferry_route.rs:213:37
|
213 | Box::new(|pos: JsValue| geo_callback(pos)) as Box<dyn Fn(JsValue)>
| ------------------------^^^^^^^^^^^^------
| | | |
| | | borrowed value does not live long enough
| | value captured here
| cast requires that `geo_callback` is borrowed for `'static`
...
221 | }
| - `geo_callback` dropped here while still borrowed
So I'm at a loss, at this point. Seems like fetching user's location would be simpler than all of this. I'm open to any path that makes any of these work. (Definition of work: I can get the user's lat/lon in the create function of a Yew Component, so that I can do some math and pass useful decisions to child components.)
Ok, I think I've got it. Or at least, I've got something that works. I'm not sure it's the most elegant solution. Basically, drop the Seed parts out of the function and just pull the coords from the JsValue, like so:
fn geo_callback(position: JsValue) {
let pos = JsCast::unchecked_into::<GeolocationPosition>(position);
let coords = pos.coords();
log::info!(
"Latitude: {}. Longitude: {}.",
coords.latitude(),
coords.longitude()
);
};
At this point, I'm pretty sure I can take those coords and do something useful with them.

Access variable after it was borrowed

I am assigning data to properties of a struct, but the following error appears:
error[E0382]: borrow of partially moved value: `super_hero`
--> src/main.rs:16:22
|
13 | for mut chunk in super_hero.description_chunks.unwrap() {
| -------- `super_hero.description_chunks` partially moved due to this method call
...
16 | println!("{:?}", &super_hero);
| ^^^^^^^ value borrowed here after partial move
|
note: this function takes ownership of the receiver `self`, which moves `super_hero.description_chunks`
--> /Users/someuser/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/option.rs:752:25
|
752 | pub const fn unwrap(self) -> T {
| ^^^^
= note: partial move occurs because `super_hero.description_chunks` has type `std::option::Option<Vec<Chunk>>`, which does not implement the `Copy` trait
help: consider calling `.as_ref()` to borrow the type's contents
|
13 | for mut chunk in super_hero.description_chunks.as_ref().unwrap() {
| +++++++++
The following is the code where I am assigning data to properties of a struct:
let super_hero_description = "several years ago.";
let mut super_hero = SuperHero::new(super_hero_description);
super_hero.description_chunks = Option::from(super_hero.get_decription_chunks(DescriptionTypes::NotVillan));
for mut chunk in super_hero.description_chunks.unwrap() {
chunk.data = Option::from(chunk.get_data(DescriptionTypes::NotVillan).await);
}
println!("{:?}", &super_hero);
The error does not happen until I try to print the super_hero at the end.
Oh, and if I follow the recommendation rust gives me
for mut chunk in super_hero.description_chunks.as_ref().unwrap() {
| +++++++++
I end up with another error:
error[E0594]: cannot assign to `chunk.data`, which is behind a `&` reference
--> src/main.rs:14:9
|
13 | for mut subdivision in super_hero.description_chunks.as_ref().unwrap() {
| ------------------------------------- this iterator yields `&` references
14 | chunk.data = Option::from(chunk.get_data()(DescriptionTypes::NotVillan).await);
| ^^^^^^^^^^^^ `chunk` is a `&` reference, so the data it refers to cannot be written
rustc is correct, it just needs a little adjustment: instead of as_ref() use as_mut(), that converts &mut Option<T> to Option<&mut T> instead of &Option<T> to Option<&T>.
The problem is that unwrap() requires an owned Option: see Reference to unwrapped property fails: use of partially moved value: `self`.

Why can't I pass a String from env::Args to Path::new?

Consider the following example:
use std::env;
use std::path::Path;
fn main() {
let args: Vec<_> = env::args().collect();
let out_path: String = args[2];
let _path = Path::new(out_path);
}
Here's the error I'm getting while compiling:
error[E0308]: mismatched types
--> main.rs:8:27
|
8 | let _path = Path::new(out_path);
| ^^^^^^^^
| |
| expected reference, found struct `std::string::String`
| help: consider borrowing here: `&out_path`
|
= note: expected type `&_`
found type `std::string::String`
Now if I follow compiler's suggestion, I get this:
error[E0507]: cannot move out of indexed content
--> main.rs:7:28
|
7 | let out_path: String = args[2];
| ^^^^^^^
| |
| cannot move out of indexed content
| help: consider using a reference instead: `&args[2]`
error: aborting due to previous error
Which, after applying the suggestion, leads me to the previous error:
error[E0308]: mismatched types
--> main.rs:7:28
|
7 | let out_path: String = &args[2];
| ^^^^^^^^
| |
| expected struct `std::string::String`, found reference
| help: consider removing the borrow: `args[2]`
|
= note: expected type `std::string::String`
found type `&std::string::String`
How can I understand the situation and solve the problem?
This was indeed an unfortunate sequence of suggestions (use a reference > remove that reference), but this was caused by the manual type ascription related to out_path.
You want a string slice, not an owned String:
let out_path: &str = &args[2];
This fits both the restriction of args (you can't move out of indexed content) and the requirements of Path::new, which requires a reference.
As for your comment, a clone() "fixes" the cannot move out of indexed content error because it doesn't require a move from the args vector - it copies an element from it instead. This fix is of course inferior to just borrowing it, which also works with Path::new.

The std documentation examples with question marks don't compile [duplicate]

This question already has answers here:
Why do try!() and ? not compile when used in a function that doesn't return Option or Result?
(4 answers)
Closed 5 years ago.
I'm having extreme difficulties with the try! and ? macro to the point that I'm starting to question the very fabric of reality. I lifted the example below straight from the rust-docs and it still blows up in my face.
Code:
pub use std::fs::File;
pub use std::io::prelude::*;
fn main() {
let mut file: File = File::open("foo.txt")?;
file.write_all(b"Hello, world!")?;
}
Error:
error[E0277]: the trait bound `(): std::ops::Try` is not satisfied
--> src/main.rs:6:23
|
6 | let mut file: File = File::open("foo.txt")?;
| ----------------------
| |
| the trait `std::ops::Try` is not implemented for `()`
| in this macro invocation
|
= note: required by `std::ops::Try::from_error`
error[E0277]: the trait bound `(): std::ops::Try` is not satisfied
--> src/main.rs:7:2
|
7 | file.write_all(b"Hello, world!")?;
| ---------------------------------
| |
| the trait `std::ops::Try` is not implemented for `()`
| in this macro invocation
|
= note: required by `std::ops::Try::from_error`
I'm on the latest stable release of Rust according to rustup (1.19.0)
These examples are currently expected to be run wrapped in a function returning a Result; if you click Run in the upper right corner of the example, you will see that it expands to:
fn main() {
use std::fs::File;
use std::io::prelude::*;
fn foo() -> std::io::Result<()> {
let mut file = File::create("foo.txt")?;
file.write_all(b"Hello, world!")?;
Ok(())
}
}
This is because functions returning Results (like File::create and io::Write::write_all) should be handled with possible errors in mind (which is especially important in documentation examples).
There was an RFC to allow returning Result from main() that was already merged, though the issue to allow ?s in main() is still active.

Resources