【问题标题】:Connect function that takes Write to function that takes Read将需要写入的函数连接到需要读取的函数
【发布时间】:2015-09-20 05:57:06
【问题描述】:

我正在探索Iron web framework for Rust 并创建了一个小型处理程序,它将读取从请求 URL 派生的图像,调整其大小,然后传递结果。据我所知,Iron Response 可以由多种不同类型构建,包括实现Read trait 的类型。

image crate 中的save function 采用实现Write trait 的类型。

感觉这两个函数应该能够连接起来,这样作者就可以写入一个缓冲区,读者可以从中读取。我找到了pipe crate,它似乎实现了这种行为,但我无法将管道的Read 末端变成 Iron 可以接受的东西。

我的函数的一个稍微简化的版本:

fn artwork(req: &mut Request) -> IronResult<Response> {
    let mut filepath = PathBuf::from("artwork/sample.png");

    let img = match image::open(&filepath) {
        Ok(img) => img,
        Err(e) => return Err(IronError::new(e, status::InternalServerError))
    };

    let (mut read, mut write) = pipe::pipe();

    thread::spawn(move || {
        let thumb = img.resize(128, 128, image::FilterType::Triangle);
        thumb.save(&mut write, image::JPEG).unwrap();
    });

    let mut res = Response::new();
    res.status = Some(iron::status::Ok);
    res.body = Some(Box::new(read));

    Ok(res)
}

我收到的错误:

src/main.rs:70:21: 70:35 error: the trait `iron::response::WriteBody` is not implemented for the type `pipe::PipeReader` [E0277]
src/main.rs:70     res.body = Some(Box::new(read));
                                   ^~~~~~~~~~~~~~

PipeReader 实现 ReadWriteBody 是为 Read 实现的,所以我觉得这应该可行。我也试过了:

let reader: Box<Read> = Box::new(read);

let mut res = Response::new();
res.status = Some(iron::status::Ok);
res.body = Some(reader);

但这给出了错误:

src/main.rs:72:21: 72:27 error: mismatched types:
 expected `Box<iron::response::WriteBody + Send>`,
    found `Box<std::io::Read>`
(expected trait `iron::response::WriteBody`,
    found trait `std::io::Read`) [E0308]
src/main.rs:72     res.body = Some(reader);
                                   ^~~~~~

如何将save 函数连接到 Iron 响应主体?

【问题讨论】:

    标签: pipe rust iron


    【解决方案1】:

    你不能在这里使用impl 代替Box&lt;Read&gt;,因为Rust 不能保证它实现了Send。如果你有一个Box&lt;Read + Send&gt;,那就是这样。不幸的是,虽然Box&lt;Read&gt; 实现了WriteBody,但Box&lt;Read + Send&gt; 没有,所以你不能使用这种类型。

    查看WriteBody 及其实现的源代码,有a commented out implementation 将实现WriteBody 用于实现Read 的所有类型,但它现在还没有编译(正如评论所说,这需要专业化,希望很快就会出现在该语言中)。

    您可以向 Iron 提交拉取请求以在 Box&lt;Read + Send&gt; 上为 WriteBody 添加一个 impl;然后,您可以使用该类型 (demo)。另一种选择是为PipeReader 定义一个包装结构并自己实现WriteBody(可能基于the implementation for Box&lt;Read&gt;)。

    【讨论】:

    • 我明白了,“特征 iron::response::WriteBody 没有为类型 Box&lt;pipe::PipeReader&gt; [E0277] 实现”在“Box::new(Box::new(read))”上。 I tried extracting the the inner box 但它随后抱怨说,“没有为 std::io::Read 类型实现发送”。
    • 查看我重写的答案。
    【解决方案2】:

    如果您可以缓冲内存中的所有内容(我认为这已经发生了),您可以使用Vec&lt;u8&gt; 加上Cursor

    use std::io::{self, Read, Write, Cursor};
    use std::borrow::BorrowMut;
    
    fn writer<W>(mut w: W) -> io::Result<()>
        where W: Write
    {
        writeln!(w, "I am the writer")
    }
    
    fn reader<R>(mut r: R) -> io::Result<String>
        where R: Read
    {
        let mut s = String::new();
        try!(r.read_to_string(&mut s));
        Ok(s)
    }
    
    fn inner_main() -> io::Result<()> {
        let mut buffer = vec![];
    
        try!(writer(&mut buffer));
        let s = try!(reader(Cursor::new(buffer.borrow_mut())));
    
        println!("Got >>{}<<", s);
    
        Ok(())
    }
    
    fn main() {
        inner_main().unwrap();
    }
    

    Cursor 跟踪您在缓冲区中的距离,以便您始终在不重新读取或覆盖现有数据的情况下进行读取或写入。

    【讨论】:

    • 谢谢,有帮助。游标实际上是我在尝试管道之前最初尝试的,但我在弄清楚如何填充缓冲区时遇到了麻烦。查看您的代码,事实证明这就像将缓冲区传递给图像保存函数一样简单,然后填充的缓冲区可以简单地传递给 Response::with 并且一切正常:gist.github.com/wezm/acf394cdb6dad315589f
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-23
    • 1970-01-01
    • 2021-09-21
    • 2020-06-22
    • 1970-01-01
    • 2013-09-30
    相关资源
    最近更新 更多