0

I've created a struct that has a &Path and two &strs. I'm trying to define a method on the struct that, given a Path-like representing a relative file path, concatenates it to the root, canonicalizes it, validates that the resulting path is contained in the root dir, and returns either a tuple of the relative and absolute paths, or an error (using a Result):

use std::path::Path;
use std::path::PathBuf;

mod error {
    use std::error;
    use std::fmt;
    use std::path;

    #[derive(Debug)]
    pub enum MediaLibraryError<'a> {
        NonAbsPath(&'a path::Path),
        NonRelPath(&'a path::Path),
    }

    impl<'a> error::Error for MediaLibraryError<'a> {
        // This is meant to be a static description of the error, without any computation!
        fn description(&self) -> &str {
            match self {
                &MediaLibraryError::NonAbsPath(_) => "File path was was expected to be absolute",
                &MediaLibraryError::NonRelPath(_) => "File path was was expected to be relative",
            }
        }
    }

    impl<'a> fmt::Display for MediaLibraryError<'a> {
        // This is the place to put formatted/computed error messages!
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            match self {
                &MediaLibraryError::NonAbsPath(x) => {
                    write!(f, r##"Path "{:?}" is not absolute"##, x)
                }
                &MediaLibraryError::NonRelPath(x) => {
                    write!(f, r##"Path "{:?}" is not relative"##, x)
                }
            }
        }
    }
}

use error::MediaLibraryError;

struct MediaLibrary<'a> {
    root_dir: &'a Path,
    item_meta_fn: &'a str,
    self_meta_fn: &'a str,
}

impl<'a> MediaLibrary<'a> {
    fn co_norm<P: AsRef<Path>>(
        &self,
        rel_sub_path: P,
    ) -> Result<(PathBuf, PathBuf), MediaLibraryError> {
        let rel_sub_path = rel_sub_path.as_ref().to_path_buf();

        if !rel_sub_path.is_relative() {
            return Err(MediaLibraryError::NonRelPath(&rel_sub_path));
        }

        let abs_sub_path = self.root_dir.join(&rel_sub_path);

        // Canonicalize.
        // Check that created absolute path is a child of root or root itself.

        Ok((rel_sub_path.to_path_buf(), abs_sub_path))
    }
}

fn main() {}

However, when trying to compile, I get this error:

error[E0597]: `rel_sub_path` does not live long enough
  --> src/main.rs:56:55
   |
56 |             return Err(MediaLibraryError::NonRelPath(&rel_sub_path));
   |                                                       ^^^^^^^^^^^^ does not live long enough
...
65 |     }
   |     - borrowed value only lives until here
   |
note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 49:5...
  --> src/main.rs:49:5
   |
49 | /     fn co_norm<P: AsRef<Path>>(
50 | |         &self,
51 | |         rel_sub_path: P,
52 | |     ) -> Result<(PathBuf, PathBuf), MediaLibraryError> {
...  |
64 | |         Ok((rel_sub_path.to_path_buf(), abs_sub_path))
65 | |     }
   | |_____^

A common beginner error, I'm sure, but for the life of me, I can't seem to figure out what to do. I've tried messing with lifetimes, trying PathBufs instead of Paths, using as_ref()/to_owned(). However, all in vain. I feel like there's a great lesson hidden in here, but I'm stumped.

P.S.: I'm using the P: AsRef<Path> as found in the docs, my understanding is that it lets one pass in a &str, Path, PathBuf, etc to the method?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Mark LeMoine
  • 4,478
  • 3
  • 31
  • 52
  • The duplicate answers more completely, but TL;DR — you can't create a variable in a function and return a reference to it. You need to return the owned value (`NonAbsPath(path::PathBuf)`). – Shepmaster Nov 03 '17 at 01:26
  • *my understanding is that it lets one pass in ...* — yes, [anything that implements `AsRef`](https://doc.rust-lang.org/std/convert/trait.AsRef.html). – Shepmaster Nov 03 '17 at 01:29
  • @Shepmaster Thank you for the link and the explanation! I'm thinking I might refactor my struct to use `PathBuf` and `String` instead, are there any gotchas to that approach to be aware of? – Mark LeMoine Nov 03 '17 at 07:44

0 Answers0