I'd like to keep an instance of the handlebars registry in a struct named "Mailer".
The instance is to be initialized upon running the "new" function of the Mailer implementation.
I do have massive problems in figuring out the proper ownership at each scope.
use handlebars::Handlebars;
pub struct Mailer<'reg> {
registry: &'reg handlebars::Handlebars<'reg>
}
impl <'reg>Mailer<'reg> {
pub fn new() -> &'reg Mailer<'reg> {
let registry = handlebars::Handlebars::new();
Mailer { registry: ®istry }
}
}
fn main() -> Result<(), std::io::Error> {
let mailer = Mailer::new();
Ok(())
}
The compiler presents these errors:
error[E0308]: mismatched types
--> src/utils/mailer.rs:9:8
|
8 | pub fn new() -> &'reg Mailer<'reg> {
| ------------------ expected `&'reg Mailer<'reg>` because of return type
...
9 | Mailer { registry: ®istry }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| expected `&Mailer<'reg>`, found struct `Mailer`
| help: consider borrowing here: `&Mailer { registry: ®istry }`
Basically I don't know how to annotate the returned Mailer Struct properly.
Simply returning
&Mailer<'req> { registry: ®istry }
instead of
Mailer { registry: ®istry }
is not a remedy at all.
I am definitely missing a lot about ownership in the Rust documentation. In my defense, I've not found any example or explanation covering struct implementations assigning other struct implementations.
I am seriously lost here.
Your new function returns a &Mailer<'_> (with lifetimes hidden), but your final expression is Mailer { ... }, which has type Mailer<'_>, not &Mailer<'_>, so you get an error.
Simply making it return &Mailer { ... } doesn't work for a different reason.
Let's imagine writing it like this, which is equivalent:
fn new() -> &'reg Mailer<'reg> {
let registry = handlebars::Handlebars::new();
let mailer = Mailer { registry: ®istry };
return &mailer;
}
In Rust, the only way to pass ownership of some data from a function to its caller is by returning it. For example, if I create a Vec in a function, and I want to pass ownership to the caller, I must return it:
fn make_vec() -> Vec<i32> {
vec![1, 2, 3]
}
The calling code takes ownership of the vec, and is therefore responsible for dropping it.
Going back to your code, you're creating a Mailer, but you're not returning it to the caller, you're only returning a reference to it. Ownership stays inside new, and so new is responsible for dropping it.
When the function returns, mailer is then dropped, since it's reached the end of the scope it was declared in, but we've kept a reference to it (by returning it to the caller). This isn't allowed, since it would allow use-after-free (using a reference to some data after that data has been dropped).
I haven't worked with handlebars in Rust before, but you probably want to change your code to look like this:
struct Mailer<'reg> {
registry: handlebars::Handlebars<'reg> // no reference here
}
impl<'reg> Mailer<'reg> {
fn new() -> Self {
let registry = handlebars::Handlebars::new();
Self { registry } // shorthand for Self { registry: registry }
}
}
The key differences are:
Mailer takes an owned Handlebars instance, rather than a reference to one
new returns an owned Mailer
This way, full ownership is passed to the caller of Mailer::new
Related
Rust normally has strict privacy laws, you can't return a private type from a public function.
However, it seems like you are able to return a type created in a closure from that closure. But why? Why are you allowed to return a private struct from a closure?
fn main () {
let closure = || {
struct Sample;
Sample
};
}
Because you can still do things with it. The structure isn't sealed inside the closure, it just so happens that we can't use the name Sample directly outside of the closure. But we can still access its methods. Consider
fn main () {
let closure = || {
struct Sample;
impl Sample {
fn say_hello(&self) {
println!("Hello, world! :)");
}
}
Sample
};
let s = closure();
s.say_hello();
}
The main function still knows that s has type Sample, and we can still call inherent methods like say_hello on it. The fact that you, as the programmer, can't say the name of the structure, is irrelevant.
Just to make it perfectly clear, based on feedback in the comments. Local structures and fn functions in Rust (i.e. structures and functions written inside other functions) are not actually local. They're internally hoisted to the enclosing module from a visibility standpoint. A function can't own a structure, only a module can. You can't reference the name Sample in the module scope, but that's where it's being hoisted to internally. If it helps, you can think of it as though Sample is being lifted to a top-level struct __mangledname_internal_Sample at the top of your file. It's still there, just not with a name that you can access.
Here's what's roughly being generated per your rust code:
struct Closure {
s : Sample
}
impl FnOnce<()> for Closure {
type Output = Sample;
fn call_once(self) -> Self::Output {
self.s
}
}
The information regarding defining the struct and the impl blocks are hoisted to the module level when inside of a closure. So this block below will be accessible at the module level:
struct Sample;
impl Sample {
fn say_hello(&self) {
println!("Hello, world! :)");
}
}
Therefore, nothing actually breaks the privacy rules as the Closure struct simply uses the Sample type defined at the module level
In your current code, you haven't yet actually done anything with the closure. Try this one:
fn main () {
let closure = some_stuff::public_function();
}
mod some_stuff {
pub fn public_function () -> impl FnOnce() -> PrivateStruct {
let closure = || {
struct PrivateStruct;
PrivateStruct
};
return closure
}
}
And you'll get
Compiling playground v0.0.1 (/playground)
error[E0412]: cannot find type `PrivateStruct` in this scope
--> src/lib.rs:6:51
|
6 | pub fn public_function () -> impl FnOnce() -> PrivateStruct {
| ^^^^^^^^^^^^^ not found in this scope
For more information about this error, try `rustc --explain E0412`.
error: could not compile `playground` due to previous error
This question already has answers here:
Why can't I store a value and a reference to that value in the same struct?
(4 answers)
Closed 5 months ago.
I am using the git2 crate and would like to get Statuses for the repo and store this in my app struct for reuse later since it is expensive to create. The problem is that Statuses references the Repository from which it was created. As far as I understand from this question: Why can't I store a value and a reference to that value in the same struct?, I can't return an owned item along with a refence to it since the address of the owned item will change when it is returned from the function and moved, thereby making the reference invalid. The below is a minimal example of what I am trying to do, what is the correct way to tackle this?
use git2::{Repository, Statuses};
struct App<'a> {
repo: Repository,
statuses: Statuses<'a>,
}
impl<'a> App<'a> {
fn new() -> Self {
let repo = Repository::open("myrepo").unwrap();
let statuses = repo.statuses(None).unwrap();
App { repo, statuses }
}
}
fn main() {
let mydata = App::new();
dbg!(mydata.statuses.len());
}
Below is the only solution I have found (also taken from the above question), which is to make Statuses optional and mutate the app data after Repository has already been returned from ::new(). This seems hacky and not idiomatic, and doesn't compile anyway.
use git2::{Repository, Statuses};
struct App<'a> {
repo: Repository,
statuses: Option<Statuses<'a>>,
}
impl<'a> App<'a> {
fn new() -> Self {
let repo = Repository::open("myrepo").unwrap();
App {
repo,
statuses: None,
}
}
}
fn main() {
let mut mydata = App::new();
mydata.statuses = mydata.repo.statuses(None).ok();
dbg!(mydata.statuses.unwrap().len());
}
error[E0597]: `mydata.repo` does not live long enough
--> src/main.rs:19:23
|
19 | mydata.statuses = mydata.repo.statuses(None).ok();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
20 | dbg!(mydata.statuses.unwrap().len());
21 | }
| -
| |
| `mydata.repo` dropped here while still borrowed
| borrow might be used here, when `mydata` is dropped and runs the destructor for type `App<'_>`
EDIT: Some additional context:
I am making an app with egui, so the App struct is the application state. Amoung other things, it will list all git repos in a directory, and display information about their statuses. I measured the repo.statuses(None).unwrap() call and and for ~10 repositories it took a total of 4ms, so too slow to call on each loop of the app. The obvious solution I could think of was to store the data in the app's state (App) but that doesn't seem possible so I'm looking for alternative approaches.
I think there are two solutions:
Copy the data you want out of the Statuses object and then release it
Use an external crate like self_cell to create a self-referential object. Note that this object can then no longer provide mut access to the Repository.
I'd argue that the first option would be the way to go in your case, because to my understanding, Statuses is simply a collection of paths with a status for each path.
use std::collections::HashMap;
use git2::{Repository, Status};
struct App {
repo: Repository,
statuses: HashMap<String, Status>,
}
impl App {
fn new() -> Self {
let repo = Repository::open(".").unwrap();
let statuses = repo
.statuses(None)
.unwrap()
.iter()
.map(|el| (el.path().unwrap().to_string(), el.status()))
.collect::<HashMap<_, _>>();
App { repo, statuses }
}
}
fn main() {
let mydata = App::new();
dbg!(mydata.statuses.len());
println!("{:#?}", mydata.statuses);
}
[src/main.rs:24] mydata.statuses.len() = 2
{
"Cargo.toml": WT_MODIFIED,
"src/main.rs": INDEX_MODIFIED | WT_MODIFIED,
}
I am having a hard time figuring out how to sort out this issue.
So I have a class ArcWorker holding a shared reference to Worker (as you can remark below).
I wrote a function in ArcWorker called join() in which the line self.internal.lock().unwrap().join(); fails with the following error:
cannot move out of dereference of std::sync::MutexGuard<'_, models::worker::Worker>
What I attempt through that line is to lock the mutex, unwrap and call the join() function from the Worker class.
As far as I understand, once that the lock function is called and it borrows a reference to self (&self), then I need some way to get to pass self by value to join (std::thread's join function requires passing self by value).
What can I do to make this work? Tried to find an answer to my question for hours but to no avail.
pub struct Worker {
accounts: Vec<Arc<Mutex<Account>>>,
thread_join_handle: Option<thread::JoinHandle<()>>
}
pub struct ArcWorker {
internal: Arc<Mutex<Worker>>
}
impl ArcWorker {
pub fn new(accounts: Vec<Arc<Mutex<Account>>>) -> ArcWorker {
return ArcWorker {
internal: Arc::new(Mutex::new(Worker {
accounts: accounts,
thread_join_handle: None
}))
}
}
pub fn spawn(&self) {
let local_self_1 = self.internal.clone();
self.internal.lock().unwrap().thread_join_handle = Some(thread::spawn(move || {
println!("Spawn worker");
local_self_1.lock().unwrap().perform_random_transactions();
}));
}
pub fn join(&self) {
self.internal.lock().unwrap().join();
}
}
impl Worker {
fn join(self) {
if let Some(thread_join_handle) = self.thread_join_handle {
thread_join_handle.join().expect("Couldn't join the associated threads.")
}
}
fn perform_random_transactions(&self) {
}
}
Since you already hold JoinHandle in an option, you can make Worker::join() take &mut self instead of self and change the if let condition to:
// note added `.take()`
if let Some(thread_join_handle) = self.thread_join_handle.take() {
Option::take() will move the handle out of the option and give you ownership over it, while leaving None in self.thread_join_handle. With this change ArcWorker::join() should compile as-is.
I have an object that I know that is inside an Arc because all the instances are always Arced. I would like to be able to pass a cloned Arc of myself in a function call. The thing I am calling will call me back later on other threads.
In C++, there is a standard mixin called enable_shared_from_this. It enables me to do exactly this
class Bus : public std::enable_shared_from_this<Bus>
{
....
void SetupDevice(Device device,...)
{
device->Attach(shared_from_this());
}
}
If this object is not under shared_ptr management (the closest C++ has to Arc) then this will fail at run time.
I cannot find an equivalent.
EDIT:
Here is an example of why its needed. I have a timerqueue library. It allows a client to request an arbitrary closure to be run at some point in the future. The code is run on a dedicated thread. To use it you must pass a closure of the function you want to be executed later.
use std::time::{Duration, Instant};
use timerqueue::*;
use parking_lot::Mutex;
use std::sync::{Arc,Weak};
use std::ops::{DerefMut};
// inline me keeper cos not on github
pub struct MeKeeper<T> {
them: Mutex<Weak<T>>,
}
impl<T> MeKeeper<T> {
pub fn new() -> Self {
Self {
them: Mutex::new(Weak::new()),
}
}
pub fn save(&self, arc: &Arc<T>) {
*self.them.lock().deref_mut() = Arc::downgrade(arc);
}
pub fn get(&self) -> Arc<T> {
match self.them.lock().upgrade() {
Some(arc) => return arc,
None => unreachable!(),
}
}
}
// -----------------------------------
struct Test {
data:String,
me: MeKeeper<Self>,
}
impl Test {
pub fn new() -> Arc<Test>{
let arc = Arc::new(Self {
me: MeKeeper::new(),
data: "Yo".to_string()
});
arc.me.save(&arc);
arc
}
fn task(&self) {
println!("{}", self.data);
}
// in real use case the TQ and a ton of other status data is passed in the new call for Test
// to keep things simple here the 'container' passes tq as an arg
pub fn do_stuff(&self, tq: &TimerQueue) {
// stuff includes a async task that must be done in 1 second
//.....
let me = self.me.get().clone();
tq.queue(
Box::new(move || me.task()),
"x".to_string(),
Instant::now() + Duration::from_millis(1000),
);
}
}
fn main() {
// in real case (PDP11 emulator) there is a Bus class owning tons of objects thats
// alive for the whole duration
let tq = Arc::new(TimerQueue::new());
let test = Test::new();
test.do_stuff(&*tq);
// just to keep everything alive while we wait
let mut input = String::new();
std::io::stdin().read_line(&mut input).unwrap();
}
cargo toml
[package]
name = "tqclient"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
timerqueue = { git = "https://github.com/pm100/timerqueue.git" }
parking_lot = "0.11"
There is no way to go from a &self to the Arc that self is stored in. This is because:
Rust references have additional assumptions compared to C++ references that would make such a conversion undefined behavior.
Rust's implementation of Arc does not even expose the information necessary to determine whether self is stored in an Arc or not.
Luckily, there is an alternative approach. Instead of creating a &self to the value inside the Arc, and passing that to the method, pass the Arc directly to the method that needs to access it. You can do that like this:
use std::sync::Arc;
struct Shared {
field: String,
}
impl Shared {
fn print_field(self: Arc<Self>) {
let clone: Arc<Shared> = self.clone();
println!("{}", clone.field);
}
}
Then the print_field function can only be called on an Shared encapsulated in an Arc.
having found that I needed this three times in recent days I decided to stop trying to come up with other designs. Maybe poor data design as far as rust is concerned but I needed it.
Works by changing the new function of the types using it to return an Arc rather than a raw self. All my objects are arced anyway, before they were arced by the caller, now its forced.
mini util library called mekeeper
use parking_lot::Mutex;
use std::sync::{Arc,Weak};
use std::ops::{DerefMut};
pub struct MeKeeper<T> {
them: Mutex<Weak<T>>,
}
impl<T> MeKeeper<T> {
pub fn new() -> Self {
Self {
them: Mutex::new(Weak::new()),
}
}
pub fn save(&self, arc: &Arc<T>) {
*self.them.lock().deref_mut() = Arc::downgrade(arc);
}
pub fn get(&self) -> Arc<T> {
match self.them.lock().upgrade() {
Some(arc) => return arc,
None => unreachable!(),
}
}
}
to use it
pub struct Test {
me: MeKeeper<Self>,
foo:i8,
}
impl Test {
pub fn new() -> Arc<Self> {
let arc = Arc::new(Test {
me: MeKeeper::new(),
foo:42
});
arc.me.save(&arc);
arc
}
}
now when an instance of Test wants to call a function that requires it to pass in an Arc it does:
fn nargle(){
let me = me.get();
Ooddle::fertang(me,42);// fertang needs an Arc<T>
}
the weak use is what the shared_from_this does so as to prevent refcount deadlocks, I stole that idea.
The unreachable path is safe because the only place that can call MeKeeper::get is the instance of T (Test here) that owns it and that call can only happen if the T instance is alive. Hence no none return from weak::upgrade
How do I get over something like this:
struct Test {
foo: Option<fn()>
}
impl Test {
fn new(&mut self) {
self.foo = Option::Some(self.a);
}
fn a(&self) { /* can use Test */ }
}
I get this error:
error: attempted to take value of method `a` on type `&mut Test`
--> src/main.rs:7:36
|
7 | self.foo = Option::Some(self.a);
| ^
|
= help: maybe a `()` to call it is missing? If not, try an anonymous function
How do I pass a function pointer from a trait? Similar to what would happen in this case:
impl Test {
fn new(&mut self) {
self.foo = Option::Some(a);
}
}
fn a() { /* can't use Test */ }
What you're trying to do here is get a function pointer from a (to use Python terminology here, since Rust doesn't have a word for this) bound method. You can't.
Firstly, because Rust doesn't have a concept of "bound" methods; that is, you can't refer to a method with the invocant (the thing on the left of the .) already bound in place. If you want to construct a callable which approximates this, you'd use a closure; i.e. || self.a().
However, this still wouldn't work because closures aren't function pointers. There is no "base type" for callable things like in some other languages. Function pointers are a single, specific kind of callable; closures are completely different. Instead, there are traits which (when implemented) make a type callable. They are Fn, FnMut, and FnOnce. Because they are traits, you can't use them as types, and must instead use them from behind some layer of indirection, such as Box<FnOnce()> or &mut FnMut(i32) -> String.
Now, you could change Test to store an Option<Box<Fn()>> instead, but that still wouldn't help. That's because of the other, other problem: you're trying to store a reference to the struct inside of itself. This is not going to work well. If you manage to do this, you effectively render the Test value permanently unusable. More likely is that the compiler just won't let you get that far.
Aside: you can do it, but not without resorting to reference counting and dynamic borrow checking, which is out of scope here.
So the answer to your question as-asked is: you don't.
Let's change the question: instead of trying to crowbar a self-referential closure in, we can instead store a callable that doesn't attempt to capture the invocant at all.
struct Test {
foo: Option<Box<Fn(&Test)>>,
}
impl Test {
fn new() -> Test {
Test {
foo: Option::Some(Box::new(Self::a)),
}
}
fn a(&self) { /* can use Test */ }
fn invoke(&self) {
if let Some(f) = self.foo.as_ref() {
f(self);
}
}
}
fn main() {
let t = Test::new();
t.invoke();
}
The callable being stored is now a function that takes the invocant explicitly, side-stepping the issues with cyclic references. We can use this to store Test::a directly, by referring to it as a free function. Also note that because Test is the implementation type, I can also refer to it as Self.
Aside: I've also corrected your Test::new function. Rust doesn't have constructors, just functions that return values like any other.
If you're confident you will never want to store a closure in foo, you can replace Box<Fn(&Test)> with fn(&Test) instead. This limits you to function pointers, but avoids the extra allocation.
If you haven't already, I strongly urge you to read the Rust Book.
There are few mistakes with your code. new function (by the convention) should not take self reference, since it is expected to create Self type.
But the real issue is, Test::foo expecting a function type fn(), but Test::a's type is fn(&Test) == fn a(&self) if you change the type of foo to fn(&Test) it will work. Also you need to use function name with the trait name instead of self. Instead of assigning to self.a you should assign Test::a.
Here is the working version:
extern crate chrono;
struct Test {
foo: Option<fn(&Test)>
}
impl Test {
fn new() -> Test {
Test {
foo: Some(Test::a)
}
}
fn a(&self) {
println!("a run!");
}
}
fn main() {
let test = Test::new();
test.foo.unwrap()(&test);
}
Also if you gonna assign a field in new() function, and the value must always set, then there is no need to use Option instead it can be like that:
extern crate chrono;
struct Test {
foo: fn(&Test)
}
impl Test {
fn new() -> Test {
Test {
foo: Test::a
}
}
fn a(&self) {
println!("a run!");
}
}
fn main() {
let test = Test::new();
(test.foo)(&test); // Make sure the paranthesis are there
}