You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: fspath.rs
    path of file: ./repos/occlum/src/libos/src/fs/file_ops
    
    the code of the file until where you have to start completion: use super::*;

pub const AT_FDCWD: i32 = -100;

pub struct FsPath<'a> {
    inner: FsPathInner<'a>,
}

#[derive(Debug)]
enum FsPathInner<'a> {
    // absolute path
    Absolute(&'a str),
    // path is relative to Cwd
    CwdRelative(&'a str),
    // Cwd
    Cwd,
    // path is relative to DirFd
    FdRelative(&'a str, FileDesc),
    // Fd
    Fd(FileDesc),
}

impl<'a> FsPath<'a> {
    /// Construct a FsPath
    pub fn new(path: &'a str, fd: i32, allow_empty_path: bool) -> Result<Self> {
        if path.len() > PATH_MAX {
            return_errno!(ENAMETOOLONG, "path name too long");
        }
        let fs_path_inner = if Path::new(path).is_absolute() {
            FsPathInner::Absolute(path)
        } else if fd >= 0 {
            if path.is_empty() {
                if !allow_empty_path {
                    return_errno!(ENOENT, "path is an empty string");
                }
                FsPathInner::Fd(fd as FileDesc)
            } else {
                let file_ref = current!().file(fd as FileDesc)?;
                let inode_file = file_ref
                    .as_inode_file()
                    .map_err(|_| errno!(EBADF, "dirfd is not an inode file"))?;
                if inode_file.metadata()?.type_ !
    
    pub fn new(path: &'a str, fd: i32, allow_empty_path: bool) -> Result<Self> {
        if path.len() > PATH_MAX {
            return_errno!(ENAMETOOLONG, "path name too long");
        }
        let fs_path_inner = if Path::new(path).is_absolute() {
            FsPathInner::Absolute(path)
        } else if fd >= 0 {
            if path.is_empty() {
                if !allow_empty_path {
                    return_errno!(ENOENT, "path is an empty string");
                }
                FsPathInner::Fd(fd as FileDesc)
            } else {
                let file_ref = current!().file(fd as FileDesc)?;
                let inode_file = file_ref
                    .as_inode_file()
                    .map_err(|_| errno!(EBADF, "dirfd is not an inode file"))?;
                if inode_file.metadata()?.type_ != FileType::Dir {
                    return_errno!(ENOTDIR, "dirfd is not a directory");
                }
                FsPathInner::FdRelative(path, fd as FileDesc)
            }
        } else if fd == AT_FDCWD {
            if path.is_empty() {
                if !allow_empty_path {
                    return_errno!(ENOENT, "path is an empty string");
                }
                FsPathInner::Cwd
            } else {
                FsPathInner::CwdRelative(path)
            }
        } else {
            return_errno!(EINVAL, "invalid dirfd number");
        };

        Ok(FsPath {
            inner: fs_path_inner,
        })
    }