I am trying to write a function that loads the standard output of a command-line utility (image-magick) into a member of a struct. I figure that since images can be may MB, I might as well avoid copies as much as possible.
/// An image data container used internally.
/// Images are 8-bit single channel for now.
pub struct Image<'a> {
/// Width of the image in pixels.
pub width: u32,
/// Height of the image in pixels.
pub height: u32,
/// The buffer containing the image data, as a slice.
pub pixels: &'a [u8],
}
// Load a file by first using imageMagick to convert it to a .pgm file.
fn load_using_magick<'a>(path: Path) -> Image<'a> {
use std::io::Command;
let output:IoResult<ProcessOutput> = Command::new("convert")
.arg("-format pgm")
.arg("-depth 8")
.arg(path)
.arg("-")
.output();
let output_unwrapped:ProcessOutput = match output {
Ok(o) => o,
Err(e) => panic!("Unable to run ImageMagick's convert tool in a separate process! convert returned: {}", e),
};
let bytes: &[u8] = match output_unwrapped.status.success() {
false => panic!("signal or wrong error code from sub-process?"),
true => output_unwrapped.output.as_slice(),
};
// Note, width and height will eventually get parsed out of "bytes"
// and the returned Imaeg.pixels will point to a slice of the (already)
// heap allocated memory. I just need to figure out ownership first...
Image{width:10,height:10,pixels:bytes}
}
The big chunk of heap that I would like to keep around was allocated by the standard library (or maybe the kernel?) when the standard library std::io::Process::Command::output() is called.
Compilation is failing with the borrow checker:
src/loaders.rs:41:17: 41:40 error: `output_unwrapped.output` does not live long enough
src/loaders.rs:41 true => output_unwrapped.output.as_slice(),
^~~~~~~~~~~~~~~~~~~~~~~
src/loaders.rs:21:51: 48:2 note: reference must be valid for the lifetime 'a as defined on the block at 21:50...
src/loaders.rs:21 fn load_using_magick<'a>(path: Path) -> Image<'a> {
src/loaders.rs:22 use std::io::Command;
src/loaders.rs:23
src/loaders.rs:24 let output:IoResult<ProcessOutput> = Command::new("convert")
src/loaders.rs:25 .arg("-format pgm")
src/loaders.rs:26 .arg("-depth 8")
...
src/loaders.rs:21:51: 48:2 note: ...but borrowed value is only valid for the block at 21:50
src/loaders.rs:21 fn load_using_magick<'a>(path: Path) -> Image<'a> {
src/loaders.rs:22 use std::io::Command;
src/loaders.rs:23
src/loaders.rs:24 let output:IoResult<ProcessOutput> = Command::new("convert")
src/loaders.rs:25 .arg("-format pgm")
src/loaders.rs:26 .arg("-depth 8")
This makes some sense to me; whatever is owning the chunk of data I'm trying to keep around is going out of scope, leaving a dangling pointer in the struct I returned by value. So how do I actually transfer ownership of the memory region to my struct before I return it?
I already read the Rust Lifetimes Manual.