I am trying to create a separate file/module that has functions that can deal with the LEDs or gyro for the stm32f3discovery. I am trying to pass the stm32f3 API that holds all of the registers into a function to then use inside.
When I run this code, I get an error saying "there is no field '###' on type '##'". How can I do this?
main.rs
#![no_std]
#![no_main]
use stm32f3::stm32f303;
mod my_api;
#[entry]
fn main() -> ! {
let periph = stm32f303::Peripherals::take().unwrap();
let gpioe = periph.GPIOE;
let rcc = periph.RCC;
my_api::led::setup_led(&gpioe, &rcc);
loop {
my_api::led::all_led_on(&gpioe);
}
}
my_api.rs
pub mod led {
pub fn setup_led<G, R>(gpio: &G, rcc: &R) {
*rcc.ahbenr.modify(|_, w| w.iopeen().set_bit()); //enables clock
*gpio.moder.modify(|_, w| {
w.moder8().bits(0b01);
w.moder9().bits(0b01);
w.moder10().bits(0b01);
w.moder11().bits(0b01);
w.moder12().bits(0b01);
w.moder13().bits(0b01);
w.moder14().bits(0b01);
w.moder15().bits(0b01)
});
}
pub fn all_led_on<G>(gpio: &G) {
*gpio.odr.modify(|_, w| {
w.odr8().set_bit();
w.odr9().set_bit();
w.odr10().set_bit();
w.odr11().set_bit();
w.odr12().set_bit();
w.odr13().set_bit();
w.odr14().set_bit();
w.odr15().set_bit()
});
}
pub fn all_led_off<G>(gpio: &G) {
*gpio.odr.modify(|_, w| {
w.odr8().clear_bit();
w.odr9().clear_bit();
w.odr10().clear_bit();
w.odr11().clear_bit();
w.odr12().clear_bit();
w.odr13().clear_bit();
w.odr14().clear_bit();
w.odr15().clear_bit()
});
}
}
Error
error[E0609]: no field `odr` on type `&G`
--> src/my_api.rs:30:15
|
29 | pub fn all_led_off <G> (gpio: &G) {
| - type parameter 'G' declared here
30 | *gpio.odr.modify(|_,w| {
| ^^^
It has this error for all of the calls onto any of the registers
Instead of using a generic to try and force our way into passing in a type that you don't know use something like:
let my_name: () = 39.2;
It will give an error that will tell you what the value on the right is and you can use that to work out what data type you can pass into the function. As shown printing variable type in rust
Related
I am trying to override/wrap the Libc vprintf(format, va_list) function with Rust code. To do so, I need to pass a VaList argument into unsafe code that also needs to catch unwind errors:
#![feature(c_variadic)]
extern crate libc;
use libc::{c_char, c_int};
pub unsafe extern "C" fn vprintf(format: *const c_char, args: std::ffi::VaList) -> c_int {
if true {
::std::panic::catch_unwind(|| hook_fn(format, args)).ok()
} else {
None
}
.unwrap_or_else(|| hook_fn(format, args))
}
pub unsafe fn hook_fn(format: *const c_char, args: std::ffi::VaList) -> c_int {
0
}
fn main() {
println!("Hello, world!");
}
My code does not compile:
error[E0277]: the type `&mut std::ffi::VaListImpl<'_>` may not be safely transferred across an unwind boundary
--> src/main.rs:8:9
|
8 | ::std::panic::catch_unwind(|| hook_fn(format, args)).ok()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------------ within this `[closure#src/main.rs:8:36: 8:60 format:&*const i8, args:std::ffi::VaList<'_, '_>]`
| |
| `&mut std::ffi::VaListImpl<'_>` may not be safely transferred across an unwind boundary
|
= help: within `[closure#src/main.rs:8:36: 8:60 format:&*const i8, args:std::ffi::VaList<'_, '_>]`, the trait `std::panic::UnwindSafe` is not implemented for `&mut std::ffi::VaListImpl<'_>`
= note: `std::panic::UnwindSafe` is implemented for `&std::ffi::VaListImpl<'_>`, but not for `&mut std::ffi::VaListImpl<'_>`
= note: required because it appears within the type `std::ffi::VaList<'_, '_>`
= note: required because it appears within the type `[closure#src/main.rs:8:36: 8:60 format:&*const i8, args:std::ffi::VaList<'_, '_>]`
Some types, especially FFI types, can cause Undefined Behaviour if used after a panic. This safety is tracked by whether or not a type implements UnwindSafe, and VaList does not.
This is explained in the first "help" line of the error message:
= help: within `[closure#src/main.rs:8:36: 8:61 format:&*const i8, args:std::ffi::VaList<'_, '_>]`,
the trait `std::panic::UnwindSafe` is not implemented for `&mut std::ffi::VaListImpl<'_>`
The first "note" also gives you a possible solution:
note: `std::panic::UnwindSafe` is implemented for `&std::ffi::VaListImpl<'_>`, but not for `&mut std::ffi::VaListImpl<'_>`
It's telling you that it is safe to share immutable references to a VaListImpl across an unwind boundary. So you can fix your code by passing the value by reference instead:
pub unsafe extern "C" fn vprintf(format: *const c_char, args: std::ffi::VaList) -> c_int {
if true {
::std::panic::catch_unwind(|| hook_fn(format, &args)).ok()
} else {
None
}
.unwrap_or_else(|| hook_fn(format, &args))
}
pub unsafe fn hook_fn(format: *const c_char, args: &std::ffi::VaList) -> c_int {
0
}
This helped fix the problem.
Not sure if this is the right way to fix this. Peter Halls suggestion above might still be right one. But it did not seem to fix the error for me.
#![feature(c_variadic)]
extern crate libc;
use libc::{c_char, c_int};
pub unsafe extern "C" fn vprintf(format: *const c_char, args: std::ffi::VaList) -> c_int {
let ap : VaListImpl = args.clone();
if true {
::std::panic::catch_unwind(|| hook_fn(format, ap.clone())).ok()
} else {
None
}
.unwrap_or_else(|| hook_fn(format, args))
}
pub unsafe fn hook_fn(format: *const c_char, args: std::ffi::VaList) -> c_int {
0
}
fn main() {
println!("Hello, world!");
}
This question already has answers here:
Is it possible to implement methods on type aliases?
(1 answer)
Rust proper error handling (auto convert from one error type to another with question mark)
(5 answers)
How to do error handling in Rust and what are the common pitfalls?
(2 answers)
Closed 2 years ago.
I have a pair of Result type aliases, AResult and BResult. AResult is from another crate, and embeds its own error type AError. I have my result (BResult) and I want to convert errors from AError to BError so I can embed them in the BResults that I return.
TIO demo
struct AError(u32);
struct BError(i64);
type AResult = Result<(), AError>;
type BResult = Result<(), BError>;
impl From<AError> for BError {
fn from(item: AError) -> Self {
(item as i64)
}
}
impl From<AResult> for BResult {
fn from(item: AResult) -> Self {
item.map_err(BError::from)
}
}
fn main() {
let result_as_a: AResult = Err(5u32);
let result_as_b = result_as_a;
if let Err(value) = result_as_b {
print!("{}", value);
}
}
I have defined a conversion for the errors from AError to BError (impl From<AError> for BError { ... }) and I'm trying to define a conversion for the Result which uses it, thinking I could do:
impl From<AResult> for BResult {
fn from(item: AResult) -> Self {
item.map_err(BError::from)
}
}
But Rust complains that I can't define things from another crate:
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> src/main.rs:12:1
|
12 | impl From<AResult> for BResult {
| ^^^^^-------------^^^^^-------
| | | |
| | | `std::result::Result` is not defined in the current crate
| | `std::result::Result` is not defined in the current crate
| impl doesn't use only types from inside the current crate
|
= note: define and implement a trait or new type instead
I'm trying to define an implementation on BResult, not AResult?!
Am I doing something very stupid? Is there a better way to do this?
I have a file that I wish to read and filter the data into two different sets and determine the number of items in each set.
use std::io::{self, BufRead};
fn main() {
let cursor = io::Cursor::new(b"pillow\nbrick\r\nphone");
let lines = cursor.lines().map(|l| l.unwrap());
let soft_count = lines.filter(|line| line.contains("pillow")).count();
let hard_count = lines.filter(|line| !line.contains("pillow")).count();
}
Playground
GitHub
However, the borrow checker gives me an error:
error[E0382]: use of moved value: `lines`
--> src/main.rs:14:22
|
8 | let lines = cursor.lines().map(|l| l.unwrap());
| ----- move occurs because `lines` has type `std::iter::Map<std::io::Lines<std::io::Cursor<&[u8; 19]>>, [closure#src/main.rs:8:36: 8:50]>`, which does not implement the `Copy` trait
9 |
10 | let soft_count = lines
| ----- value moved here
...
14 | let hard_count = lines
| ^^^^^ value used here after move
I tried getting around this using reference counting to allow multiple ownership:
use std::io::{self, BufRead};
use std::rc::Rc;
fn main() {
let cursor = io::Cursor::new(b"pillow\nbrick\r\nphone");
let lines = Rc::new(cursor.lines().map(|l| l.unwrap()));
let soft_count = Rc::clone(&lines)
.filter(|line| line.contains("pillow"))
.count();
let hard_count = Rc::clone(&lines)
.filter(|line| !line.contains("pillow"))
.count();
}
Playground
Github
I get a similar error message:
error[E0507]: cannot move out of an `Rc`
--> src/main.rs:11:22
|
11 | let soft_count = Rc::clone(&lines)
| ^^^^^^^^^^^^^^^^^ move occurs because value has type `std::iter::Map<std::io::Lines<std::io::Cursor<&[u8; 19]>>, [closure#src/main.rs:9:44: 9:58]>`, which does not implement the `Copy` trait
error[E0507]: cannot move out of an `Rc`
--> src/main.rs:15:22
|
15 | let hard_count = Rc::clone(&lines)
| ^^^^^^^^^^^^^^^^^ move occurs because value has type `std::iter::Map<std::io::Lines<std::io::Cursor<&[u8; 19]>>, [closure#src/main.rs:9:44: 9:58]>`, which does not implement the `Copy` trait
You cannot. Instead, you will need to clone the iterator, or some building block of it. In this case, the highest thing you can clone is the Cursor:
use std::io::{self, BufRead};
fn main() {
let cursor = io::Cursor::new(b"pillow\nbrick\r\nphone");
let lines = cursor.clone().lines().map(|l| l.unwrap());
let lines2 = cursor.lines().map(|l| l.unwrap());
let soft_count = lines.filter(|line| line.contains("pillow")).count();
let hard_count = lines2.filter(|line| !line.contains("pillow")).count();
}
For an actual File, you will need to use try_clone as it might fail. In either case, you will be referring to the same data twice and only the iterator information will be kept.
For your specific case, you don't need any of this. In fact, iterating over the data twice is inefficient. The simplest built-in thing you can do is to partition the iterator:
let (softs, hards): (Vec<_>, Vec<_>) = lines.partition(|line| line.contains("pillow"));
let soft_count = softs.len();
let hard_count = hards.len();
This is still a bit inefficient as you don't need the actual values. You could create your own type that implements Extend and discards the values:
#[derive(Debug, Default)]
struct Count(usize);
impl<T> std::iter::Extend<T> for Count {
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator,
{
self.0 += iter.into_iter().count();
}
}
let (softs, hards): (Count, Count) = lines.partition(|line| line.contains("pillow"));
let soft_count = softs.0;
let hard_count = hards.0;
You could also just use a for loop or build something on top of fold:
let (soft_count, hard_count) = lines.fold((0, 0), |mut state, line| {
if line.contains("pillow") {
state.0 += 1;
} else {
state.1 += 1;
}
state
});
The following code fails to compile
// winservice.rs
#[macro_use] extern crate err_derive;
extern crate windows_service;
use windows_service::service_manager::{ServiceManager, ServiceManagerAccess};
#[derive(Debug, Error)]
pub enum WinServiceError {
#[error(display = "could not query windows services api")]
WinApiError(windows_service::Error),
}
impl From<windows_service::Error> for WinServiceError {
fn from(error: windows_service::Error) -> Self {
WinServiceError::WinApiError(error)
}
}
fn get_manager(request_access: ServiceManagerAccess) -> Result<ServiceManager, WinServiceError> {
ServiceManager::local_computer(None::<&str>, request_access)
}
pub fn main() {
// get_manager();
}
I am getting the error
error[E0308]: mismatched types
--> src/winservice.rs:186:5
|
185 | fn get_manager(request_access: ServiceManagerAccess) -> Result<ServiceManager, Error> {
| ----------------------------- expected `std::result::Result<windows_service::service_manager::ServiceManager, winservice::Error>` because of return type
186 | ServiceManager::local_computer(None::<&str>, request_access)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `winservice::Error`, found enum `windows_service::Error`
|
= note: expected type `std::result::Result<_, winservice::Error>`
found type `std::result::Result<_, windows_service::Error>`
Why isn't the Rust compiler auto converting the return type from windows_service::Error to winservice::Error?
Thanks to #Shepmaster's help, I was able resolve the error.
I did not realize that I was returning the result object directly. I had to unwrap the result object for the conversion to work.
The following code attempts to return a value of type Result<_, windows_services::Error> as Result<_, WinServiceError>.
fn get_manager(request_access: ServiceManagerAccess) -> Result<ServiceManager, WinServiceError> {
ServiceManager::local_computer(None::<&str>, request_access)
}
But the following code works, because we are now creating a new Result object of the correct signature, and rust compiler performs the conversion between the error types while creating the new object.
fn get_manager(request_access: ServiceManagerAccess) -> Result<ServiceManager, WinServiceError> {
Ok(ServiceManager::local_computer(None::<&str>, request_access)?)
}
I have a trait
trait B {
type Index: Sized + Copy;
fn bounds(&self) -> (Self::Index, Self::Index);
}
I want to get all the Indexes within bounds:
fn iterate<T: B>(it: &T) {
let (low, high) = it.bounds();
for i in low..high {}
}
This won't work since there's no constraint that the type T can be "ranged" over, and the compiler says as much:
error[E0277]: the trait bound `<T as B>::Index: std::iter::Step` is not satisfied
--> src/main.rs:8:5
|
8 | for i in low..high {}
| ^^^^^^^^^^^^^^^^^^^^^ the trait `std::iter::Step` is not implemented for `<T as B>::Index`
|
= help: consider adding a `where <T as B>::Index: std::iter::Step` bound
= note: required because of the requirements on the impl of `std::iter::Iterator` for `std::ops::Range<<T as B>::Index>`
I tried adding the Step bound to Index
use std::iter::Step;
trait B {
type Index: Sized + Copy + Step;
fn bounds(&self) -> (Self::Index, Self::Index);
}
but apparently it isn't stable:
error: use of unstable library feature 'step_trait': likely to be replaced by finer-grained traits (see issue #42168)
--> src/main.rs:1:5
|
1 | use std::iter::Step;
| ^^^^^^^^^^^^^^^
error: use of unstable library feature 'step_trait': likely to be replaced by finer-grained traits (see issue #42168)
--> src/main.rs:4:32
|
4 | type Index: Sized + Copy + Step;
| ^^^^
Am I missing something or is it just not possible to do so right now?
If you want to require that a Range<T> can be iterated over, just use that as your trait bound:
trait Bounded {
type Index: Sized + Copy;
fn bounds(&self) -> (Self::Index, Self::Index);
}
fn iterate<T>(it: &T)
where
T: Bounded,
std::ops::Range<T::Index>: IntoIterator,
{
let (low, high) = it.bounds();
for i in low..high {}
}
fn main() {}
To do this kind of thing generically the num crate is helpful.
extern crate num;
use num::{Num, One};
use std::fmt::Debug;
fn iterate<T>(low: T, high: T)
where
T: Num + One + PartialOrd + Copy + Clone + Debug,
{
let one = T::one();
let mut i = low;
loop {
if i > high {
break;
}
println!("{:?}", i);
i = i + one;
}
}
fn main() {
iterate(0i32, 10i32);
iterate(5u8, 7u8);
iterate(0f64, 10f64);
}