In my understanding, asynchronous can only handle I/O intensive tasks such as reading and writing sockets or files, but can do nothing with CPU intensive tasks such as encryption and compression.
So in Rust Tokio Runtime, I think only need to use spawn_blocking to handle CPU intensive tasks. But I have seen this repo, the example is
#[tokio_02::main]
async fn main() -> Result<()> {
    let data = b"example";
    let compressed_data = compress(data).await?;
    let de_compressed_data = decompress(&compressed_data).await?;
    assert_eq!(de_compressed_data, data);
    println!("{:?}", String::from_utf8(de_compressed_data).unwrap());
    Ok(())
}
This library crates adaptors between compression and async I/O types.
I have 3 questions:
- What is the purpose of awaiting compress/decompress? 
- Are these adaptors necessary or my understanding of asynchrony wrong? 
- Can I do compression operations directly in Tokio multithreaded runtime? Like this 
async fn foo() {
    let mut buf = ...;
    compress_sync(&mut buf);
    async_tcp_stream.write(buf).await;
}
 
     
    