nb icon indicating copy to clipboard operation
nb copied to clipboard

Add block_while! macro that blocks while another expression evaluates to true

Open kellerkindt opened this issue 6 years ago • 5 comments

I am using this macro derivative for an private project for a while now and decided to see whether others (like you) can make use of it as well. Basically it adds a condition to block! so that it does not block indefinitely. This allows code like this:

// ...
        let time = || info.uptime_ms();
        let timeout = time() + 500;
        let in_time = || timeout > time();

        block_while!(in_time(), tx.write(START_BYTE))
            .and(block_while!(in_time(), tx.write(0x01)))
            .and(block_while!(in_time(), tx.write(COMMAND)))
            .and(block_while!(in_time(), tx.write(0x00)))
            .and(block_while!(in_time(), tx.write(0x00)))
            .and(block_while!(in_time(), tx.write(0x00)))
            .and(block_while!(in_time(), tx.write(0x00)))
            .and(block_while!(in_time(), tx.write(0x00)))
            .and(block_while!(in_time(), tx.write(0x79)))
            .map_err(drop)
            .and_then(|_| {
                Ok([
                    block_while!(in_time(), rx.read()).map_err(drop)?,
                    block_while!(in_time(), rx.read()).map_err(drop)?,
                    block_while!(in_time(), rx.read()).map_err(drop)?,
                    block_while!(in_time(), rx.read()).map_err(drop)?,
                    block_while!(in_time(), rx.read()).map_err(drop)?,
                    block_while!(in_time(), rx.read()).map_err(drop)?,
                    block_while!(in_time(), rx.read()).map_err(drop)?,
                    block_while!(in_time(), rx.read()).map_err(drop)?,
                    block_while!(in_time(), rx.read()).map_err(drop)?,
                ])
            })
            . // ...
// ...

The operation is still blocking but in this case has a timeout for the whole operation.

kellerkindt avatar Jun 30 '19 13:06 kellerkindt

This sounds fine to me. However it has been lying around for quite a while. Does anybody else have concerns about it @rust-embedded/hal ?

eldruin avatar Jun 30 '20 16:06 eldruin

Looks mostly okay to me. I do find the "rewrapping" a bit weird.

Can't we just do:

...
            match $e {
                Err($crate::Error::Other(_)) => {
                    #[allow(unreachable_code)]
                    break $e
                },
...

therealprof avatar Jul 05 '20 11:07 therealprof

Looks mostly okay to me. I do find the "rewrapping" a bit weird.

I agree. Good point. @therealprof: $e is a Result, you probably meant:

match $e {
    Err($crate::Error::WouldBlock) => {
        if !$c {
            break Err($crate::Error::WouldBlock);
        }
    },
    Err(e) => {
        #[allow(unreachable_code)]
        break Err(e)
    },
    Ok(x) => break Ok(x),
}

@kellerkindt Would you do this change, rebase to master and add an example to the documentation?

eldruin avatar Jul 05 '20 16:07 eldruin

@therealprof: $e is a Result, you probably meant:

Nope, I meant $e, as long as you're not moving the item whatever you're matching on (if in doubt, use a reference), you can just reuse it. Not sure whether that's not possible in case due to macro hygiene or something...

therealprof avatar Jul 05 '20 16:07 therealprof

@therealprof: $e is a Result, you probably meant:

Nope, I meant $e, as long as you're not moving the item whatever you're matching on (if in doubt, use a reference), you can just reuse it. Not sure whether that's not possible in case due to macro hygiene or something...

Interesting! I assumed the matching branch would move it and thus drop it on _ but I tried it and it works just fine. Thanks! @kellerkindt please disregard my comment.

eldruin avatar Jul 05 '20 18:07 eldruin