Initialise struct field as temporary directory and read from directory

179 Views Asked by At

I am trying to have a struct which has a field which I assume should be of type Result<TempDir>. When I initialise an implementation of the field with new(), I would like that particular field to be initialised by the creation of a new temp directory. Later, I want to implement a method to read from that directory.

Here's the code, I am more worried about the syntax and proper use of libraries (why exactly are there over four libraries for read/write buffering in Rust, this is insane) as the logic should be right. Dont worry too much about the trait implementations, I just need directions in the syntax. Please don't be too harsh, as I know it doesn't compile, but with just two changes it should.

    extern crate rustc_back;
    use std::path::Path;
    use std::fs::File;
    use rustc_back::tempdir::TempDir as TempDir;
    pub struct MyStorage {

      temp_dir : Result<TempDir>
    }

    impl MyStorage {
      pub fn new() -> MyStorage { 
        //tempo = match TempDir::new("encrypt_storage");
        let store = match TempDir::new("encrypt_storage") {
          Ok(dir) => dir,
            Err(e) => panic!("couldn't create temporary directory: {}", e)
        };

        MyStorage { temp_dir: store }
        //MyStorage { temp_dir: TempDir::new("encrypt_storage") }
      }
    }

    impl Storage for MyStorage {
      fn get(&self, name: Vec<u8>) -> Vec<u8> {
    //let mut f = std::fs::File::open(self.temp_dir.path() / name);
    let mut f = std::fs::File::open(&self.temp_dir){
        // The `desc` field of `IoError` is a string that describes the error
        Err(why) => panic!("couldn't open: {}", why.description()),
        Ok(file) => file,
    };
    let mut s = String::new();
    //f.read_to_string(&mut s);
    match f.read_to_string(&mut s){
        Err(why) => panic!("couldn't read: {}", why.description()),
        Ok(_) => print!("contains:\n{}", s),
    }
    s.to_vec()
  }

  fn put(&mut self, name: Vec<u8>, data: Vec<u8>) {
    // self.entries.push(Entry { name : name, data : data })
    let mut f = File::create(self.temp_dir.path() / name);
    f.write_all(data);
  }

      fn put(&mut self, name: Vec<u8>, data: Vec<u8>) {
        // self.entries.push(Entry { name : name, data : data })
        let mut f = File::create(self.temp_dir.path() / name);
        f.write_all(data);
      }
    }
1

There are 1 best solutions below

5
Shepmaster On

After fixing the indentation (Rust uses 4 spaces per level), removing the Storage for since you didn't provide that trait, removing commented-out code, and adding a main, you are left with this:

extern crate rustc_back;
use std::path::Path;
use std::fs::File;
use rustc_back::tempdir::TempDir as TempDir;

pub struct MyStorage {
    temp_dir : Result<TempDir>
}

impl MyStorage {
    pub fn new() -> MyStorage { 
        let store = match TempDir::new("encrypt_storage") {
            Ok(dir) => dir,
            Err(e) => panic!("couldn't create temporary directory: {}", e)
        };

        MyStorage { temp_dir: store }
    }
}

impl MyStorage {
    fn get(&self, name: Vec<u8>) -> Vec<u8> {
        let mut f = std::fs::File::open(self.temp_dir.path() / name);
        let mut s = String::new();
        f.read_to_string(&mut s);
        s.to_vec()
     }

    fn put(&mut self, name: Vec<u8>, data: Vec<u8>) {
        let mut f = File::create(self.temp_dir.path() / name);
        f.write_all(data);
    }
}

fn main() {}

Compiling that has this error:

error: wrong number of type arguments: expected 2, found 1 [E0243]
temp_dir : Result<TempDir>
           ^~~~~~~~~~~~~~~

Which nicely points to the problematic type. Let's look at the docs for Result, which includes the definition:

pub enum Result<T, E> {
    Ok(T),
    Err(E),
} 

So Result has two type parameters - T is used for the success case, and E is used for the failure case. Your code is only specifying one of them. My guess is that you looked at the docs for TempDir and copy-and-pasted:

fn new(prefix: &str) -> Result<TempDir>

However, if you click on the Result there, you'll see it goes to io::Result, which is simply a type alias that binds E to io::Error:

type Result<T> = Result<T, Error>; 

With all that exposition out of the way, you can "fix" your problem by changing your MyStorage struct:

pub struct MyStorage {
    temp_dir: std::io::Result<TempDir>,
}

And then you will get another compiler error, as you are already dealing with the Result via the match in MyStorage::new. You aren't storing a io::Result<TempDir>, you are just storing a TempDir! Changing your struct further:

pub struct MyStorage {
    temp_dir: TempDir,
}

unlocks a whole new set of errors for you to figure out; but now you have gotten past that first hurdle!