arc object has method lock from mutex as instance method - rust

I have a struct Db.
struct Db {
entries: Arc<Mutex<HashMap<String, String>>>
}
impl Db {
pub fn new() -> Db {
Db {
entries: Arc::new(Mutex::new(Hashmap::new()))
}
}
}
let db = Db::new();
db.entries.lock() // works fine returning &Result<MutexLock>
I am having a hard time understanding how a method lock() is accessible on the Arc object.
Per the documentation for Arc, Arc<T> will implement Send and Sync as long as the T implements Send and Sync.. Mutex implements Send and Sync hence Arc must also be implementing it. I traced the code and found the following guard clause.
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: ?Sized + Sync + Send> Send for Arc<T> {}
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> {
What I am not understanding is how can the .lock() method on the Arc object return the Result<MutexGuard<HashMap<...>>>
When I hover and ctrl + click on the lock method it takes me to the mutex.rs. Isn't it supposed to take me to an instance method of the Arc module or and some trait which was implemented in the Arc module? I am confused at this point. If anyone can help me understand?

Arc implements Deref trait which "gives" you access to the methods of the enclosed object as the if those methods were implemented on the Arc itself.
It's a syntactic sugar, as far as I understand.
This syntactic sugar is the reason you should use fully qualified syntax if you want to call Arc methods.
use std::sync::Arc;
let arc = Arc::new(());
// Method-call syntax
let arc2 = arc.clone();
// Fully qualified syntax
let arc3 = Arc::clone(&arc);

Related

Multible trait objects of the same instance wrapped by Arc<Mutex<_>>

The goal is to have an object (callback_handler) implementing the traits A, B and C that can be passed to different functions that expect a trait object of type A or B, for instance.
This requires callback_handler, and the trait objects to be protected by the same Mutex (since, e.g., trait A expects &mut self). Furthermore, for this setup to work, this Mutex must be wrapped in an Arc or Rc:
use std::sync::{Arc, Mutex};
trait A {
fn a(&mut self) {}
}
trait B {}
trait C: A + B {}
struct Foo {}
impl A for Foo {}
impl B for Foo {}
impl C for Foo {}
fn register_for_A(callback_handler: Arc<Mutex<Box<dyn A>>>) {
// Register for callbacks defined in `A`.
// Store the passed handler somewhere.
}
fn register_for_B(callback_handler: Arc<Mutex<Box<dyn B>>>) {
// Register for callbacks defined in `B`.
// Store the passed handler somewhere.
}
fn main() {
let callback_handler = Arc::new(Mutex::new(Box::new(Foo{})));
// Register for callbacks using different trait objects of the same "origin" object.
// For this to be safe, all objects must be protected by the same ("shared") mutex.
// !!! This will not work since there must be some steps to cast this to the right type. !!!
register_for_A(Arc::clone(&callback_handler));
register_for_B(Arc::clone(&callback_handler));
// We can still use `callback_handler` to call methods on Foo ourself
}
Now, the question is, how can the origin object callback_hanlder of type Arc<Mutex<Box<Foo>>> be casted/converted to an Arc<Mutex<Box<dyn A>>> and Arc<Mutex<Box<dyn B>>>?
While I don't see a technical reason why this should not be possible, I don't know how to perform such a conversion and whether it is doable. While one solution would be using the Any trait, I was hoping that there is a solution that retains compile-time type safety for functions register_for_A and register_for_B.
You're getting tripped up by your double use of smart pointers Box + Arc you can simply cast an Arc<Mutex<Foo>> to an Arc<Mutex<dyn A>> using as, there is really no need to additionally Box it:
use std::sync::{Arc, Mutex};
trait A {
fn a(&mut self) {}
}
trait B {}
struct Foo {}
impl A for Foo {}
impl B for Foo {}
fn register_for_A(callback_handler: Arc<Mutex<dyn A>>) {
// Register for callbacks defined in `A`.
// Store the passed handler somewhere.
}
fn register_for_B(callback_handler: Arc<Mutex<dyn B>>) {
// Register for callbacks defined in `B`.
// Store the passed handler somewhere.
}
fn main() {
let callback_handler = Arc::new(Mutex::new(Foo{}));
// Register for callbacks using different trait objects of the same "origin" object.
// For this to be safe, all objects must be protected by the same ("shared") mutex.
// !!! This will not work since there must be some steps to cast this to the right type. !!!
register_for_A(Arc::clone(&callback_handler) as _);
register_for_B(Arc::clone(&callback_handler) as _);
// We can still use `callback_handler` to call methods on Foo ourself
}

Rust member functions as multithreaded mutable callbacks in real-time safe code

I am looking to use a member function of a struct as a mutable callback. The standard way I would do this is by wrapping my struct instance in a mutex and then in an Arc. In this use case however, my callback is a real-time audio callback which needs to be real-time safe and is triggered on a dedicated thread. This means no locking can happen that might delay the callback from occurring.
My actual member callback method must take a mutable reference to the struct (I think this is where things fall apart). The struct does contain members but these can all be atomic variables.
Here is an example of the kind of thing I'm looking for:
use std::sync::Arc;
use clap::error;
use cpal::{traits::{HostTrait, DeviceTrait}, StreamConfig, OutputCallbackInfo, StreamError};
use std::sync::atomic::AtomicI16;
pub struct AudioProcessor {
var: AtomicI16,
}
impl AudioProcessor {
fn audio_block_f32(&mut self, audio: &mut [f32], _info: &OutputCallbackInfo) {
}
fn audio_error(&mut self, error: StreamError) {
}
}
fn initAudio()
{
let out_dev = cpal::default_host().default_output_device().expect("No available output device found");
let mut supported_configs_range = out_dev.supported_output_configs().expect("Could not obtain device configs");
let config = supported_configs_range.next().expect("No available configs").with_max_sample_rate();
let proc = Arc::new(AudioProcessor{var: AtomicI16::new(5)});
let audio_callback_instance = proc.clone();
let error_callback_instance = proc.clone();
out_dev.build_output_stream(&StreamConfig::from(config), move |audio: &mut [f32], info: &OutputCallbackInfo| audio_callback_instance.audio_block_f32(audio, info), move |stream_error| error_callback_instance.clone().audio_error(stream_error));
}
Currently this code fails in the build_output_stream() function with this error message:
cannot borrow data in an Arc as mutable
trait DerefMut is required to modify through a dereference, but it is not implemented for Arc<AudioProcessor>
Are there any standard ways of dealing with problems like this?

How to accept either ownerhip or mutable reference for the same method

I am making a library in Rust around a TCP protocol. And I am also trying to make it async runtime independent.
I would like to make it accept ownership of an existing connection OR accept a mutable reference to it. I.e. I want to let the caller say who should drop the connection.
I have this
pub struct ReadableStream<T: AsyncRead + AsyncWrite> {
reader: FramedRead<ReadHalf<T>, WordCodec>,
}
pub struct WriteableStream<T: AsyncRead + AsyncWrite> {
writer: FramedWrite<WriteHalf<T>, WordCodec>,
}
pub struct AsyncStream<T: AsyncRead + AsyncWrite> {
read_stream: ReadableStream<T>,
write_stream: WriteableStream<T>,
}
impl<T: AsyncRead + AsyncWrite> From<T> for AsyncStream<T> {
fn from(stream: T) -> Self {
let parts = stream.split();
Self {
read_stream: ReadableStream::new(parts.0),
write_stream: WriteableStream::new(parts.1),
}
}
}
impl<'stream, T: AsyncRead + AsyncWrite + Unpin> From<&'stream mut T>
for AsyncStream<&'stream mut T>
{
fn from(stream: &'stream mut T) -> Self {
let parts = stream.split();
Self {
read_stream: ReadableStream::new(parts.0),
write_stream: WriteableStream::new(parts.1),
}
}
}
But this fails to compile with "conflicting implementation for AsyncStream<&mut _>". If I uncomment the second implementation, the first one compiles. I can also compile only the second one... But I want to have both. I would expect either to be called based on whether from() was called like AsyncStream::from(source) or like AsyncStream::from(&mut source).
So how could I accomplish that?
Note: FramedRead/FramedWrite are from asynchronous-codec. AsyncRead, AsyncWrite, ReadHalf, WriteHalf are from the futures crate. WordCodec is my implementation of the protocol tailored to asynchronous-codec that is irrelevant to the question at hand.
I decided what I thought is biting the bullet by implementing a method in my struct ( AsyncStream ) to do the conversion, and maybe implement From for the specific runtimes I plan to test against, enabling users to use the struct's method when their runtime is not covered.
This approach works... but furthermore than that, it revealed that what I was trying to do is not exactly feasible for a different reason. I want to have the ability to split the connection into reader and writer, and I can't do that since split() takes ownership.
I'll solve the ownership/mutable reference problem by accepting ownership only, and providing a method that consumes self and returns the wrapped stream. Not exactly the ergonomics I was hoping for, but it addresses the scenario about wanting to let the user use my lib from a point, to a point, and switch from/to something else.

How to defer lifetime checking to runtime

I'm trying to pass a non-static closure into tokio. Obviously this doesn't work. Is there a way to make sure the lifetimes are appropriate at runtime? Here's what I tried:
Attempt with Arc
In order to not pass the closure directly into tokio, I put it into the struct that manages our timers:
type Delays<'l, K: Eq + Hash + Debug + Copy + Send> = HashMap<K, Box<dyn FnOnce() + 'l + Send>>;
pub struct Timers<'l, K: Eq + Hash + Debug + Clone + Send> {
delays: Arc<Mutex<Delays<'l, K>>>,
}
The impl for that struct lets us easily add and remove timers. My plan was to somehow pass a static closure into tokio, by only moving a Weak reference
to the mutexed hashmap:
// remember handler function
delays.insert(key.clone(), Box::new(func));
// create a weak reference to the delay map to pass into the closure
let weak_handlers = Arc::downgrade(&self.delays);
// task that runs after a delay
let task = Delay::new(Instant::now() + delay)
.map_err(|e| warn!("Tokio timer error: {}", e)) // Map the error type to ()
.and_then(move |_| {
// get the handler from the table, of which we have only a weak ref.
let handler = Weak::upgrade(&weak_handlers)
.ok_or(())? // If the Arc dropped, return an error and thus aborting the future
.lock()
.remove(&key)
.ok_or(())?; // If the handler isn't there anymore, we can abort aswell.
// call the handler
handler();
Ok(())
});
So with the Weak we make sure that we abort, if the hash table was dropped.
It's important to know that the lifetime 'l is the same as that of the Timers struct, but how can I tell the compiler? Also, I think the real problem is that Weak<T>: 'static is not satisfied.
Writing it myself using unsafe
I tried building something similar to Sc to achieve this. First, is Sc going to work here? I read the code and understand it. I can't see any obvious problems - though it was kind of hard to come to the conclusion that the map method is actually safe, because the reference will definitely be dropped at the end of the map and not stored somewhere.
So I tried to adapt Sc for my needs. This is only a rough outline and I know there are some issues with this, but I believe something like this should be possible:
Have a struct Doa<T> that will own T
Doa::ref(&self) -> DoaRef<T> will produce a opaque object that internally contain a *const u8 to the owned object.
DoaRef doesn't contain references with non-static lifetimes and thus can be passed to tokio.
Have impl<T> Drop for Doa<T> that sets that *const u8 to null
So the DoaRef can now check if the value still exists and get a reference to it.
I also tried to make sure that the lifetime of &self in ref must be longer than the lifetimes of references in T, to ensure this works only if Doa really lives longer than the object the pointer points to.
struct Doa<'t, T: 'l> { ... }
pub fn ref(&'s self) -> DoaRef<T> where 't: 'a
But then T is lifetime-contrained and since DoaRef is parameterized over it DoaRef: 'static doesn't hold anymore.
Or is there some crate, or maybe even something in std that can do this?

How can I share references across threads?

I am unable to share a reference between threads.
trait Facade { /*some functions*/ }
struct Client<'a> {
facade: &'a mut Facade,
join_grd: thread::JoinGuard<'a()>,
}
impl<'a> Client<'a> {
pub fn new(my_facade: &'a mut Facade) -> Client<'a> {
Client {
facade: my_facade,
join_grd: thread::scoped(|| Client::start(my_facade)),
}
}
fn start(my_facade: &'a mut Facade) { unimplemented!() }
}
Given my newbie status in Rust, I'm getting confused with concepts and errors. How do I achieve the above ?
I'm pretty sure you can't do this due to the mutable aliasing guarantees in Rust. In Rust you can't have two mutable references to the same thing at the same time, but this is exactly what happens in your code: you store my_facade to the field of Client and at the same time you are trying to pass it to start() method in another thread. This would require having two mutable references to the same Facade which is disallowed.
The actual errors which compiler emits on your code are caused by that you're using a non-moving closure. If you change thread::scoped() instantiation to this:
join_grd: thread::scoped(move || Client::start(my_facade))
the error would be more sensible:
test.rs:16:60: 16:69 error: cannot move `my_facade` into closure because it is borrowed
test.rs:16 join_grd: thread::scoped(move || Client::start(my_facade))
^~~~~~~~~
test.rs:15:21: 15:30 note: borrow of `*my_facade` occurs here
test.rs:15 facade: my_facade,
^~~~~~~~~
This essentially means that since &mut references are unique and are moved instead of copied, you can't duplicate them. Similar code with the regular & reference instead of &mut (and an additional Sync parent trait on Facade) works fine.
You have to rethink your architecture to fix this error. It is difficult to understand what you want from this piece of code alone, so I can't give any exact advices, but you may consider using Arc and Mutex if you want to share mutable state between threads.
Naive usage of Arc/Mutex like this:
fn start(my_facade: Arc<Mutex<Facade>>)
won't work because Facade is a trait, not a regular type. When you use traits as types, you're in fact opting into dynamic dispatch in form of trait objects. In short, trait objects can't be used directly; they should always be behind a pointer. Your original program also used trait objects (&'a mut Facade is a trait object). Ideally we should be able to form trait objects with any kind of smart pointer, and ideally Arc<Mutex<Facade>> should work, but unfortunately for now trait objects can only be created with &, &mut or Box:
fn start(my_facade: Arc<Mutex<Box<Facade>>>)
This is the reason of the error about Sized that you observe.
However, you should also consider not using trait objects at all and just use generics:
trait Facade: Send { fn f(&self); }
struct Client<'a, F: Facade> { // '
facade: Arc<Mutex<F>>,
join_grd: thread::JoinGuard<'a, ()>, // '
}
impl<'a, F: Facade+'a> Client<'a, F> { // '
pub fn new(my_facade: Arc<Mutex<F>>) -> Client<'a, F> { // '
let my_facade_2 = my_facade.clone(); // clone the Arc pointer
Client {
facade: my_facade,
join_grd: thread::scoped(move || Client::start(my_facade_2)),
}
}
fn start(my_facade: Arc<Mutex<F>>) { unimplemented!() }
}
You also need to add Send bound either on the trait itself (as in the example above) or on F type variable (as in F: Facade+Send+'a) because only Send data may be transferred between threads safely, so you need to specify that F is Send, either directly or as a supertrait constraint on Facade.

Resources