# How to filter an async stream

**URL:** <https://users.rust-lang.org/t/how-to-filter-an-async-stream/40565>\
**Category:** help\
**Created:** [April 7, 2020, 6:51am UTC](https://users.rust-lang.org/t/how-to-filter-an-async-stream/40565 "2020-04-07T06:51:09Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![coldgrnd](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/coldgrnd/32/1414_2.png) [@coldgrnd](https://users.rust-lang.org/u/coldgrnd)\
**Post date:** [April 7, 2020, 6:51am UTC](https://users.rust-lang.org/t/how-to-filter-an-async-stream/40565/1 "2020-04-07T06:51:09Z")

</div>

What's the best way to filter an async stream? The types are kind of confusing to me.  
example: [read\_dir](https://docs.rs/async-std/1.5.0/async_std/fs/fn.read_dir.html)

I have a predicate that I want to apply to the stream like this:

```rust
async fn is_match(p: impl AsRef<Path>) -> bool

```

then I want to collect the results into a `Vec<PathBuf>`  
So the function that I would want to write is this:

```rust
async fn read_dir_filtered<P: AsRef<Path>>(path: P) -> Result<Vec<PathBuf>>

```

which in turn needs to uses `is_match`.  
Ideas for this?

---

<div class="post-metadata">

**Author:** ![alice](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/alice/32/9777_2.png) [@alice](https://users.rust-lang.org/u/alice)\
**Post date:** [April 7, 2020, 7:36am UTC](https://users.rust-lang.org/t/how-to-filter-an-async-stream/40565/2 "2020-04-07T07:36:13Z")

</div>

If you just need to create a vector, you can adapt the example on the `read_dir` function:

```rust
use async_std::fs;
use async_std::prelude::*;

let mut entries = fs::read_dir(".").await?;

while let Some(res) = entries.next().await {
    let entry = res?;
    println!("{}", entry.file_name().to_string_lossy());
}

```

Just add an if here to skip the ones you don't want.

---

<div class="post-metadata">

**Author:** ![coldgrnd](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/coldgrnd/32/1414_2.png) [@coldgrnd](https://users.rust-lang.org/u/coldgrnd)\
**Post date:** [April 7, 2020, 2:40pm UTC](https://users.rust-lang.org/t/how-to-filter-an-async-stream/40565/3 "2020-04-07T14:40:35Z")

</div>

Thanks for your reply @alice! Your suggestion is valid.  
for completeness: I tried to get it working with `filter_map` and this is what now seems to work for me:

```rust
use anyhow::{Context, Result};
use async_std::{
    fs,
    path::{Path, PathBuf},
};
use futures::stream::{Stream, StreamExt};
use std::ffi::OsStr;

async fn read_dir_filtered<P: AsRef<Path>>(
    ending: &'static str,
    path: P,
) -> Result<std::pin::Pin<Box<dyn Stream<Item = PathBuf>>>> {
    let dir_stream = fs::read_dir(&path)
        .await
        .with_context(|| format!("failed to read: {:?}", path.as_ref()))?;
    Ok(Box::pin(dir_stream.filter_map(move |d| async move {
        match d {
            Ok(rr) if path_has_ending(rr.path(), ending) => Some(rr.path().to_path_buf()),
            Ok(_) | Err(_) => None,
        }
    })))
}

fn path_has_ending(p: impl AsRef<Path>, ending: &str) -> bool {
    match p.as_ref().extension().and_then(OsStr::to_str) {
        Some(ext) => ending == ext,
        _ => false,
    }
}

```

---

<div class="post-metadata">

**Author:** ![system](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/system/32/51372_2.png) [@system](https://users.rust-lang.org/u/system)\
**Post date:** [July 6, 2020, 2:40pm UTC](https://users.rust-lang.org/t/how-to-filter-an-async-stream/40565/4 "2020-07-06T14:40:44Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
