Как преобразовать итератор байтов в поток в Rust - PullRequest
3 голосов
/ 19 июня 2020

Я пытаюсь разработать функцию, которая требует чтения содержимого файла в futures::stream::BoxStream, но мне сложно понять, что мне нужно делать.

У меня есть выяснил, как читать файл байтом за байтом через Bytes, который реализует итератор.

use std::fs::File;
use std::io::prelude::*;
use std::io::{BufReader, Bytes};

// TODO: Convert this to a async Stream
fn async_read() -> Box<dyn Iterator<Item = Result<u8, std::io::Error>>> {
    let f = File::open("/dev/random").expect("Could not open file");
    let reader = BufReader::new(f);

    let iter = reader.bytes().into_iter();
    Box::new(iter)
}

fn main() {
    ctrlc::set_handler(move || {
        println!("received Ctrl+C!");
        std::process::exit(0);
    })
    .expect("Error setting Ctrl-C handler");

    for b in async_read().into_iter() {
        println!("{:?}", b);
    }
}

Однако я изо всех сил пытался выяснить, как я могу превратить этот Box<dyn Iterator<Item = Result<u8, std::io::Error>>> в Stream.

Я бы подумал, что что-то вроде этого сработает:

use futures::stream;
use std::fs::File;
use std::io::prelude::*;
use std::io::{BufReader, Bytes};

// TODO: Convert this to a async Stream
fn async_read() -> stream::BoxStream<'static, dyn Iterator<Item = Result<u8, std::io::Error>>> {
    let f = File::open("/dev/random").expect("Could not open file");
    let reader = BufReader::new(f);

    let iter = reader.bytes().into_iter();
    std::pin::Pin::new(Box::new(stream::iter(iter)))
}

fn main() {
    ctrlc::set_handler(move || {
        println!("received Ctrl+C!");
        std::process::exit(0);
    })
    .expect("Error setting Ctrl-C handler");

    while let Some(b) = async_read().poll() {
        println!("{:?}", b);
    }
}

Но я продолжаю получать массу ошибок компилятора, я пробовал другие перестановки, но, как правило, не получал ни к чему.

Одна из ошибок компилятора: 1016

std::pin::Pin::new
``` --> src/main.rs:14:24
   |
14 |     std::pin::Pin::new(Box::new(stream::iter(iter)))
   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::iter::Iterator`, found enum `std::result::Result`
1018 Если у меня что-то не так, не стесняйтесь поправлять меня.

Для некоторой дополнительной информации я пытаюсь сделать это, чтобы вы могли CTRL-C вне команды в nushell

1 Ответ

3 голосов
/ 19 июня 2020

Я думаю, вы немного усложняете его, вы можете просто вернуть impl Stream из async_read, нет необходимости в коробках или булавках (то же самое касается исходной версии на основе Iterator). Затем вам нужно настроить среду выполнения asyn c, чтобы опросить поток (в этом примере я просто использую среду выполнения, предоставленную futures::executor::block_on). Затем вы можете вызвать futures::stream::StreamExt::next() в потоке, чтобы получить будущее, представляющее следующий элемент.

Вот один из способов сделать это:

use futures::prelude::*;
use std::{
    fs::File,
    io::{prelude::*, BufReader},
};

fn async_read() -> impl Stream<Item = Result<u8, std::io::Error>> {
    let f = File::open("/dev/random").expect("Could not open file");
    let reader = BufReader::new(f);
    stream::iter(reader.bytes())
}

async fn async_main() {
    while let Some(b) = async_read().next().await {
        println!("{:?}", b);
    }
}

fn main() {
    ctrlc::set_handler(move || {
        println!("received Ctrl+C!");
        std::process::exit(0);
    })
    .expect("Error setting Ctrl-C handler");

    futures::executor::block_on(async_main());
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...