Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
    Ukonn Ra
    @UkonnRa
    @tanriol Hi, drop the lock? You mean std::mem::drop? But it is still blocking...
    use tokio::sync::{broadcast};
    use tokio::sync::broadcast::Sender;
    use tokio::stream::StreamExt;
    use tokio::time::Duration;
    use std::sync::{Arc};
    use futures::lock::Mutex;
    
    struct App(Sender<i32>, Vec<i32>);
    
    impl App {
        fn new(sender: &Sender<i32>) -> Self {
            Self(sender.clone(), Default::default())
        }
    
        fn start(app: Arc<Mutex<App>>) {
            // 3. Receiver: Receive data and do something
            tokio::spawn(async move {
                println!("Start spawn");
                let mut app_locked = app.lock().await;
                tokio::pin! {
                    let stream = app_locked.0.subscribe().into_stream().filter(Result::is_ok).map(Result::unwrap);
                };
                std::mem::drop(app_locked);
    
                while let Some(i) = stream.next().await {
                    tokio::time::sleep(Duration::from_secs(i as u64 % 2)).await;
                    println!("receive: {}", i);
                    app.lock().await.1.push(i);
                }
                println!("Stream finished");
            });
        }
    }
    
    #[tokio::main]
    async fn main() {
        let (tx, _rx) = broadcast::channel(128);
        let app = Arc::new(Mutex::new(App::new(&tx)));
    
        // 1. Provider: Send data continuously
        tokio::spawn(async move {
            for i in 0..10_i32 {
                tx.send(i).unwrap();
            }
        });
    
    
        // 2. Monitor: Check the status every second and print log
        let app_cloned = app.clone();
        tokio::spawn(async move {
            let mut cnt = 1;
            let mut vec_size = 0;
    
            loop {
                let app_locked = app_cloned.lock().await;
                vec_size = app_locked.1.len();
                println!("#{}: vec size: {}", cnt, vec_size);
                std::mem::drop(app_locked);
    
                if vec_size >= 10 {
                    break;
                } else {
                    cnt += 1;
                }
    
                tokio::time::sleep(Duration::from_secs(1)).await;
            }
        });
    
        tokio::time::sleep(Duration::from_secs(1)).await;
    
        App::start(app.clone());
    
        loop {}
    
    }
    And it still returns:
    #1: vec size: 0
    #2: vec size: 0
    Start spawn
    #3: vec size: 0
    #4: vec size: 0
    #5: vec size: 0
    #6: vec size: 0
    Denis Lisov
    @tanriol
    You also need to fix sequencing :-) your Provider sends all data in one batch before the App is started, and the broadcast channel is documented to receive only values sent after the subscription happens.
    Ukonn Ra
    @UkonnRa
    It works! So which means the lock should be:
    1. dropped ASAP once your mutation work finished
    2. you should wait all sender being created before sending the real message
    @tanriol Helped me a lot! Thanks
    Félix Lesc.
    @EpiFouloux
    Hello, If I try to create a file and write in it in an async method should I use the threadpool? (block)
    Denis Lisov
    @tanriol
    @UkonnRa Dropping the lock ASAP is a good practice, but the most important part of it is to drop it for the time you spend waiting (sleeping). Speaking about waiter creation... why do you pass your Sender to the App at all when it actually needs the Receiver?
    @EpiFouloux Depends on your requirements :-) if they are lax enough, you can just do that in your async method.
    Ukonn Ra
    @UkonnRa

    @tanriol Because you it you use Sender, you cannot into_stream, Sender does not implement Copy or Clone:

    use tokio::sync::{broadcast};
    use tokio::sync::broadcast::{Sender, Receiver};
    use tokio::stream::StreamExt;
    use tokio::time::Duration;
    use std::sync::{Arc};
    use futures::lock::Mutex;
    
    struct App(Receiver<i32>, Vec<i32>);
    
    impl App {
        fn new(recv: Receiver<i32>) -> Self {
            Self(recv, Default::default())
        }
    
        fn start(app: Arc<Mutex<App>>) {
            // 3. Receiver: Receive data and do something
            tokio::spawn(async move {
                println!("Start spawn");
                let mut app_locked = app.lock().await;
                tokio::pin! {
                    let stream = app_locked.0.into_stream().filter(Result::is_ok).map(Result::unwrap);
                };
                std::mem::drop(app_locked);
    
                while let Some(i) = stream.next().await {
                    tokio::time::sleep(Duration::from_secs(i as u64 % 2)).await;
                    println!("receive: {}", i);
                    app.lock().await.1.push(i);
                }
                println!("Stream finished");
            });
        }
    }
    
    #[tokio::main]
    async fn main() {
        let (tx, rx) = broadcast::channel(128);
        let app = Arc::new(Mutex::new(App::new(rx)));
    
    
        App::start(app.clone());
    
        tokio::time::sleep(Duration::from_secs(1)).await;
    
        // 1. Provider: Send data continuously
        tokio::spawn(async move {
            for i in 0..10_i32 {
                tx.send(i).unwrap();
                tokio::time::sleep(Duration::from_millis(500)).await;
            }
        });
    
        // 2. Monitor: Check the status every second and print log
        let app_cloned = app.clone();
        let mut cnt = 1;
        let mut vec_size = 0;
    
        loop {
            let app_locked = app_cloned.lock().await;
            vec_size = app_locked.1.len();
            println!("#{}: vec size: {}", cnt, vec_size);
            std::mem::drop(app_locked);
    
            if vec_size >= 10 {
                break;
            } else {
                cnt += 1;
            }
    
            tokio::time::sleep(Duration::from_secs(1)).await;
        }
    
    }

    Will raise errors:

    error[E0507]: cannot move out of dereference of `futures::lock::MutexGuard<'_, App>`
      --> src\main.rs:21:30
       |
    21 |                 let stream = app_locked.0.into_stream().filter(Result::is_ok).map(Result::unwrap);
       |                              ^^^^^^^^^^^^ move occurs because value has type `tokio::sync::broadcast::Receiver<i32>`, which does not implement the `Copy` trait
    Denis Lisov
    @tanriol
    @UkonnRa Sure, but there are ways around that. For example, passing it directly to start, or storing it in an Option and using take, or using recv in your loop instead of into_stream...
    Ukonn Ra
    @UkonnRa
    @tanriol thanks for advice! I'll figure out a way to solve it
    Goldstein
    @GoldsteinE

    Hi!
    I'm trying to check code for one specific lint with

    $ cargo +nightly clippy -- -A clippy::all -W clippy::never_loop

    but get this warning + warnings from other lints:

    warning: lint name `all` is deprecated and does not have an effect anymore. Use: clippy::all
      |
      = note: requested on the command line with `-A all`
    Oh, my bad, it seems that clippy just cached command-line flags
    Krzysiek Bochenek
    @kpbochenek

    Hi, I am playing around with writing text editor supporting LSP, for drawing GUI I use SDL which basically boils down to loop:

    loop { 
      handle_events();
      // I want to add something like handle_lsp_events();
      update_window();
      redraw
    }

    I spawn a new process with Command::new("lsp_server") and set stdin/stdout to piped().
    Then I try stdout.read(&mut buf).unwrap() but it blocks.
    I thought because it returns number of bytes received I would simply loop getting 0 most of time here but it looks like 0 means end of stream.
    How to handle this? As I am learning rust any readings/tutorials/snippets on this topic would be great!

    Denis Lisov
    @tanriol
    How often do you try to read the reply? :-)
    Krzysiek Bochenek
    @kpbochenek
    so far 60fps => 60 times per sec. Does it matter?
    Denis Lisov
    @tanriol
    To Rust - not really. To your users... well, if your user is using a laptop on battery, an editor waking up every 16 ms is... suboptimal for battery life :-)
    If you don't use an async runtime, I'd suggest moving this functionality to a separate thread and using the proper SDL way (messages?) to notify the main loop. However, I'm not really sure whether SDL supports that.
    Krzysiek Bochenek
    @kpbochenek
    Any tutorials you could recommend for communicating between threads?
    Denis Lisov
    @tanriol
    Sorry, but for proper integration with the SDL event loop this should be done the SDL way, and I'm not familiar with that one.
    chama-chomo
    @chama-chomo
    Hello, anyone able to help with Cursive lib? Any idea how can i for one selection use on_select() as well as on_submit() callback methods?
    ret394
    @ret394
    @chama-chomo If you have access to a Rust repl use that to see if methods are supported on the selection object.
    chama-chomo
    @chama-chomo
    oh thx, i've solved it already

    I have another question, though. I have Vec<Machine> and I'd need to get only machine struct fullfilling certain criteria, not the vec anymore. How can I achieve that?
    something like below with input: hosts_data: &Vec<Machine>

                let host: Machine = hosts_data.iter().filter(|&s| s.name.as_deref() == Some(selection)).collect();

    thx

    ret394
    @ret394
    No idea.
    chama-chomo
    @chama-chomo
    same here :)
    ret394
    @ret394
    Why don't you try to get all the and then store the ones that you like?
    chama-chomo
    @chama-chomo
    there will be only one after it passes filter, so I don't want to keep it in the Vec anymore
    ret394
    @ret394
    Does anyone know if Rust is installed by default on Raspi 3 or Rpi 4? Scratch is for some reason.
    @chama-chomo Will there be only one in all cases?
    chama-chomo
    @chama-chomo
    yes
    Denis Lisov
    @tanriol
    @chama-chomo .iter().find(|&entry| ...)
    chama-chomo
    @chama-chomo
    lemme try, thx
    Denis Lisov
    @tanriol
    (would also need unwrap or other handling for the "sorry, no such entry" case)
    chama-chomo
    @chama-chomo
    seems this is what i needed, indeed. Thx again!
    ret394
    @ret394

    At least make the 'LLVM IR' and assembly output easy to copy. If more tabs -> yes.

    1. Expand macros using stable version.

    These must be a long standing request from users. ;-)
    Now it should be clear.


    Is Miri good or bad? What do you think.

    Denis Lisov
    @tanriol
    Miri is mostly unnecessary as long as you're only writing safe code, and is really important if you're doing some unsafe magic.
    ret394
    @ret394

    Of course you will have to do unsafe magic.

    I could be a bit ticked off, due to the kids at Github messing with me. Everything's messed up. 🤷‍♀️

    Jason Kiniry
    @jtk18

    Is anyone here familiar enough with serde to help with a deserialization issue? How would one represent a structure like:

    {
       "branch" : [
          [
             16,
             {
                "text" : "wantarray ? :"
             }
          ]
        ]
    }

    I went with something like:

    #[derive(Debug, Deserialize)]
    pub(crate) struct File {
        #[serde(flatten)]
        pub branch: Vec<Vec<Branch>>,
    }

    For the outer bit, but no amount of trial and error has made how to construct the "Branch" struct clearly. Any help would be really appreciated!

    Denis Lisov
    @tanriol
    @jtk18 I'd say that Branch should be an enum (or use an enum during deserialization)
    Jason Kiniry
    @jtk18
    @tanriol I tried using https://github.com/vityafx/serde-aux/blob/master/src/field_attributes.rs#L275 in a manual deserialization method, but I get Error("data did not match any variant of untagged enum StringOrInt"
    Denis Lisov
    @tanriol
    Sure, because { "text": "..." } is not a string and not an int :-)
    Rom Grk
    @romgrk
    hey, where can I find good tutorials or documentation on how to create data in rust? I have this recurrent problem where I need to create data from other data (eg return two PathBufs generated from a single PathBuf). I try to do it in a function to keep things neat and tidy, but I'm always hit by cannot return value referencing local variable -_- any tips?
    1 reply
    Want NoEmailSpam
    @ret394_gitlab

    Rust beginner woes 10101

    Some examples of better syntax off the top of my head, that disable the spurious warnings. And the subsequent mitigations.

    // Each line is one example
    #[allow(unused_variables)]
    #[no(warn_unused_variables)]

    The new syntax would be non-intrusive, moving forward in time. For straightforward reasons.

    Currently you can either rename each of the variables. Or you have to patch the component that is the source here. Or not use Rust lang as it seems like a language that you don't want on your devices.


    For reference -
    rust-lang/rust#3266

    This is a real world example of why I don't like discussions that don't solve the problem.

    Also I don't care about the reasons, if anyone is feeling too defensive about decisions. Small things like this get out of focus pretty easily when you are building an actual open source language driven by feedback.

    Denis Lisov
    @tanriol
    @ret394_gitlab I don't exactly understand your problem, but yes, the allow(unused_variables) attribute silences that warning.
    prographo
    @prographo
    how do i concatenate two strings
    Denis Lisov
    @tanriol
    @prographo If this is just a one-off operation, format!("{}{}", string1, string2) is likely the easiest way.
    Note, however, that if you want to build a big buffer by concatenating this is not a good choice.