struct Floor{
requestHandler: Option<RequestHandler>
}
struct RequestHandler{
uri: StrBuf,
handler: fn() -> StrBuf
}
impl Floor {
fn do_something(&self){
//(&self.requestHandler.unwrap().handler)();
//expected function but found `&fn() -> std::strbuf::StrBuf`
//(*(&self.requestHandler.unwrap().handler))();
//cannot move out of dereference of `&`-pointer
//(self.requestHandler.unwrap().handler)();
//cannot move out of dereference of `&`-pointer
}
}
fn main() {
let foo = Floor {
requestHandler: None
};
foo.do_something();
}
In do_something I try to get to my fn which is stored on the handler property of my RequestHandler struct.
Whatever I try, I just seem to be unable to call it (see the compiler messages beneath my failed attempts in the code).
The problem is the signature of Option.unwrap:
impl Option<T> {
fn unwrap(self) -> T { ... }
}
That is, it is taking the Option by value. RequestHandler has to move when used by value, since StrBuf moves (specifically StrBuf isn't Copy which forces RequestHandler to also not be Copy).
The correct way to handle this is to call Option.as_ref:
impl Option<T> {
fn unwrap<'r>(&'r self) -> Option<&'r T> { ... }
}
That is, it takes a reference to an Option and gives you an Option containing a reference to what the original Option contained, this means that .unwrap will then give you that reference, pointing to the RequestHandler inside self, to handle as you wish.
(self.requesthandler.as_ref().unwrap().handler)()
Related
This question is written for Yew v0.19
Asynchronous foreign JavaScript functions can be used in Rust through Closures, as the function to pass-in:
#[wasm_bindgen]
extern "C" {
fn setInterval(closure: &Closure<dyn FnMut()>, time: u32) -> i32;
}
// ...
let cb = Closure::new(|| {
log("interval elapsed!");
});
let interval_id = setInterval(&cb, 1_000);
This is nice for a pedantic examples, but Closures have a critical requirement - the function applied needs to have a 'static lifetime. Likewise, with Yew applications, a perfect mechanism for spontaneous response is the Message enum, and having it update() the Model. However, the link() mechanism in Context (which issues messages) does not have a static lifetime.
In an ideal world, the value submitted to the closure could just be applied as a Yew component message:
struct Model {
thing: Option<JsValue>,
}
enum Msg {
GotThing(JsValue),
}
#[wasm_bindgen]
extern "C" {
fn createThing(closure: &Closure<dyn FnMut(JsValue) -> ());
}
impl Component for Model {
type Message = Msg;
type Properties = ();
fn create(_ctx: &Context<Self>) -> Self {
Model {
thing: None, // initial value
}
}
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Msg::GotThing(x) => { // handle the message
self.thing = Some(x);
true
},
}
}
fn rendered(&mut self, ctx: &Context<Self>, first_render: bool) {
if first_render {
let cb: Box<dyn FnMut(JsValue) -> ()> = Box::new(|x| {
// try and issue the message
ctx.link().send_message(Msg::GotThing(x));
// ^ doesn't have a `'static` lifetime! Won't compile
});
createThing(Closure::wrap(&cb));
}
}
// fn view() ... omitted, not relevant
}
I'm wondering if there's a way to convert a Callback into a Closure, or if there's a better, more canonical way to do this, to please correct me.
Another idea I had would use some kind of queue defined statically (which wouldn't be safe as it's a mutable static variable), but then it could be used as an intermediary data type between the Closure passed to createThing, and messages could be dispatched within the component.
Maybe there's an external way to interact with a Yew component that I'm overlooking? I'm not sure how to resolve this issue. What would be the most correct way to achieve this goal?
I have the following problem:
I have two structs A and B, A implements a method, which takes another method as argument. I then create an instance of A within B. I then call the method of A with a method of B as argument. However, the passed method of B contains self as argument, since I have to access some other fields of B within the passed method.
My current plan would be to pass the method itself and self referencing an instance of B to the method in A. However, I struggle with the type definitions. I can hardcode the type of the second parameter to be B, however, I would like to keep it open, in case a struct C would also like to use the method in A. I therefore would like to set the type of the second parameter to the type of the struct, where the method in the first parameter is originating. Is there a way for achieving this? I was thinking about generics, however, I was not yet able to implement it.
Edit: added a minimal example in rust playground. What bothers me about this code, is, that I want to get rid of the hard coded &B in some_func_a, since this does not work with struct C.
struct A {}
impl A {
fn some_func_a(&self, passed_fn: fn(&B, i32), cur_self: &B) {
passed_fn(cur_self, 21);
}
}
struct B {
some_val: i32,
}
struct C {
some_val: u32, // different field here than in B
}
impl B {
fn call_fn_in_a(&self, a: A) {
a.some_func_a(B::some_func_b, self);
}
fn some_func_b(&self, passed_val: i32) {
println!("The value is {}, passed was {}", self.some_val, passed_val)
}
}
impl C {
fn call_fn_in_a(&self, a: A) {
// this line here breaks, since &B is hard coded
a.some_func_a(C::some_func_c, self);
}
fn some_func_c(&self, passed_val: i32) {
println!("this is a new function, val is {}, passed was {}", self.some_val, passed_val)
}
}
fn main() {
let a = A {};
let b = B {
some_val: 42,
};
let b = B {
some_val: 42,
};
b.call_fn_in_a(a);
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=53ac44cb660d180b3c7351e394355692
It sounds like you want a closure instead of a function pointer. This would allow you to eliminate the extra parameter of A::some_func_a() altogether:
impl A {
fn some_func_a(&self, passed_fn: impl FnOnce(i32) -> ()) {
passed_fn(21);
}
}
Now we can call this function with any closure matching the call signature. For example:
impl B {
fn call_fn_in_a(&self, a: A) {
a.some_func_a(|v| self.some_func_b(v));
}
fn some_func_b(&self, passed_val: i32) {
println!("The value is {}, passed was {}", self.some_val, passed_val)
}
}
And likewise for C.
Now there are no restrictions on what extra data the function needs. Before there wasn't even a way to express the situation where the callback didn't need the reference parameter. Now it doesn't matter because the closure can capture what it needs, and it's no longer A::some_func_a()'s responsibility.
(Playground)
Side note: you probably want your call_fn methods to take the A by reference (&A), not by value. Otherwise calling these functions consumes the A value, requiring you to make another one to call the functions again.
I'm working with a library that uses Rust types to keep track of state. As a simplified example, say you have two structs:
struct FirstStruct {}
struct SecondStruct {}
impl FirstStruct {
pub fn new() -> FirstStruct {
FirstStruct {}
}
pub fn second(self) -> SecondStruct {
SecondStruct {}
}
// configuration methods defined in this struct
}
impl SecondStruct {
pub fn print_something(&self) {
println!("something");
}
pub fn first(self) -> FirstStruct {
FirstStruct {}
}
}
And to actually use these structs you usually follow a pattern like so, after printing you may stay in second state or go back to first state depending on how you're using the library:
fn main() {
let first = FirstStruct::new();
let second = first.second(); // consumes first
second.print_something();
// go back to default state
let _first = second.first();
}
I want to create my own struct that handles the state changes internally and simplifies the interface. This also lets me have a single mutable reference around that I can pass to other functions and call the print method. Using it should look something like this:
fn main() {
let mut combined = CombinedStruct::new(FirstStruct::new());
combined.print();
}
I've come up with the following solution that works, at least in this simplified example:
enum StructState {
First(FirstStruct),
Second(SecondStruct),
}
struct CombinedStruct {
state: Option<StructState>,
}
impl CombinedStruct {
pub fn new(first: FirstStruct) -> CombinedStruct {
CombinedStruct {
state: Some(StructState::First(first)),
}
}
pub fn print(&mut self) {
let s = match self.state.take() {
Some(s) => match s {
StructState::First(first) => first.second(),
StructState::Second(second) => second,
},
None => panic!(),
};
s.print_something();
// If I forget to do this, then I lose access to my struct
// and next call will panic
self.state = Some(StructState::First(s.first()));
}
}
I'm still pretty new to Rust but this doesn't look right to me. I'm not sure if there's a concept I'm missing that could simplify this or if this solution could lead to ownership problems as my application gets more complicated. Is there a better way to do this?
Playground link
I once had a similar problem and went basically with your solution, but I avoided the Option.
I.e. I basically kept your
enum StructState {
First(FirstStruct),
Second(SecondStruct),
}
If an operation tries to convert a FirstStruct to a SecondStruct, I introduced a function try_to_second roughly as follows:
impl StructState {
fn try_to_second(self) -> Result<SecondState, StructState> {
/// implementation
}
}
In this case, an Err indicates that the StructState has not been converted to SecondStruct and preserves the status quo, while an Ok value indicates successfull conversion.
As an alternative, you could try to define try_to_second on FirstStruct:
impl FirstStruct {
fn try_to_second(self) -> Result<FirstStruct, SecondStruct> {
/// implementation
}
}
Again, Err/Ok denote failure/success, but in this case, you have more concrete information encoded in the type.
I have a function like this:
extern {
fn foo(layout: *const RawLayout) -> libc::uint8_t;
}
fn bar(layout: Layout) -> bool {
unsafe {
foo(&layout.into() as *const _) != 0
}
}
Where Layout is a copyable type that can be converted .into() a RawLayout.
I want to make sure I understand what is happening as it is unsafe. As I understand it, layout.into() creates a temporary RawLayout, then & takes a reference to it, and as *const _ converts it to a raw pointer (*const RawLayout). Then the foo() function is called and returns, and finally the temporary RawLayout is dropped.
Is that correct? Or is there some tricky reason why I shouldn't do this?
You are right. In this case, foo is called first and RawLayout is dropped afterwards. This is explained in The Rust Reference (follow the link to see concrete examples of how this works out in practice):
The lifetime of temporary values is typically the innermost enclosing
statement
However, I would rather follow Shepmaster's advice. Explicitly introducing a local variable would help the reader of the code concentrate in more important things, like ensuring that the unsafe code is correct (instead of having to figure out the exact semantics of temporary variables).
How to check this
You can use the code below to check this behavior:
struct Layout;
struct RawLayout;
impl Into<RawLayout> for Layout {
fn into(self) -> RawLayout {
RawLayout
}
}
impl Drop for RawLayout {
fn drop(&mut self) {
println!("Dropping RawLayout");
}
}
unsafe fn foo(layout: *const RawLayout) -> u8 {
println!("foo called");
1
}
fn bar(layout: Layout) -> bool {
unsafe {
foo(&layout.into() as *const _) != 0
}
}
fn main() {
bar(Layout);
}
The output is:
foo called
Dropping RawLayout
I'm trying to apply some OOP but I'm facing a problem.
use std::io::Read;
struct Source {
look: char
}
impl Source {
fn new() {
Source {look: '\0'};
}
fn get_char(&mut self) {
self.look = 'a';
}
}
fn main() {
let src = Source::new();
src.get_char();
println!("{}", src.look);
}
Compiler reports these errors, for src.get_char();:
error: no method named get_char found for type () in the current
scope
and for println!("{}", src.look);:
attempted access of field look on type (), but no field with that
name was found
I can't find out what I've missed.
Source::new has no return type specified, and thus returns () (the empty tuple, also called unit).
As a result, src has type (), which does not have a get_char method, which is what the error message is telling you.
So, first things first, let's set a proper signature for new: fn new() -> Source. Now we get:
error: not all control paths return a value [E0269]
fn new() -> Source {
Source {look: '\0'};
}
This is caused because Rust is an expression language, nearly everything is an expression, unless a semicolon is used to transform the expression into a statement. You can write new either:
fn new() -> Source {
return Source { look: '\0' };
}
Or:
fn new() -> Source {
Source { look: '\0' } // look Ma, no semi-colon!
}
The latter being the more idiomatic in Rust.
So, let's do that, now we get:
error: cannot borrow immutable local variable `src` as mutable
src.get_char();
^~~
Which is because src is declared immutable (the default), for it to be mutable you need to use let mut src.
And now it all works!
Final code:
use std::io::Read;
struct Source {
look: char
}
impl Source {
fn new() -> Source {
Source {look: '\0'}
}
fn get_char(&mut self) {
self.look = 'a';
}
}
fn main() {
let mut src = Source::new();
src.get_char();
println!("{}", src.look);
}
Note: there is a warning because std::io::Read is unused, but I assume you plan to use it.