2015-09-20 6 views
3

Я изучаю Iron web framework for Rust и создал небольшой обработчик, который будет считывать изображение, полученное из URL-адреса запроса, изменять его размер и затем доставлять результат. Из того, что я могу сказать, Iron Response может быть построен из нескольких различных типов, включая типы, которые реализуют Read trait.Функция подключения, которая берет запись в функцию, которая принимает Чтение

save function в image crate принимает тип, который реализует 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 реализует Read и WriteBody реализуется для 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 функцию тела ответа Железного?

ответ

1

Вы не можете использовать impl для Box<Read> здесь, потому что Rust не может гарантировать, что он реализует Send. Если бы у вас был Box<Read + Send>, это было бы так. К сожалению, в то время как Box<Read> реализует WriteBody, Box<Read + Send> этого не делает, поэтому вы не можете использовать этот тип.

Глядя на исходный код для WriteBody и его реализации, есть a commented out implementation, что бы реализовать WriteBody для всех типов, которые реализуют Read, но он не компилируется как сейчас (как говорится в комментариях, это требует специализации, которая, мы надеемся, скоро придет на язык).

Вы можете отправить запрос на тягу к утюгу, чтобы добавить impl для WriteBody на Box<Read + Send>; то вы можете использовать этот тип (demo). Другой вариант - определить структуру обертки для PipeReader и самостоятельно реализовать WriteBody (возможно, на основе the implementation for Box<Read>).

+0

Я получаю: «черта' iron :: response :: WriteBody' не реализована для типа 'Box ' [E0277] "в поле« Box :: new »(Box :: new (читать))".[Я попытался извлечь внутренний ящик] (https://gist.github.com/wezm/a45b751a62c44a878623), но затем жалуется, что «Send» не реализован для типа «std :: io :: Read'». – Wes

+0

См. Мой переписанный ответ. –

0

Если вы хорошо с буферизацией все в памяти (и я думаю, что это то, что уже происходит), вы можете просто использовать Vec<u8> плюс 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 отслеживает, как далеко вы находитесь в буфер, чтобы вы всегда читали или записывали без повторного чтения или перезаписи существующих данных.

+0

Спасибо, это помогло. Курсор на самом деле был тем, что я пробовал, прежде чем пытаться использовать трубку, но у меня возникли проблемы с настройкой заполнения буфера. Посмотрев на ваш код, получается, что это так же просто, как передать буфер функции сохранения изображения, а затем заполненный буфер можно просто передать в Response :: с, и все это работает: https://gist.github.com/ wezm/acf394cdb6dad315589f – Wes

Смежные вопросы