#pragma once #if !defined(MIJIN_VIRTUAL_FILESYSTEM_MAPPING_HPP_INCLUDED) #define MIJIN_VIRTUAL_FILESYSTEM_MAPPING_HPP_INCLUDED 1 #include #include "./filesystem.hpp" #include "../internal/common.hpp" namespace mijin { // // public defines // // // public constants // // // public types // template class MappingFileSystemAdapter : public FileSystemAdapter { private: TWrapped wrapped_; fs::path root_; public: template explicit MappingFileSystemAdapter(fs::path root, TArgs&&... args) : wrapped_(std::forward(args)...), root_(std::move(root)) {} MappingFileSystemAdapter(const MappingFileSystemAdapter&) = default; MappingFileSystemAdapter(MappingFileSystemAdapter&&) MIJIN_NOEXCEPT = default; MappingFileSystemAdapter& operator=(const MappingFileSystemAdapter&) = default; MappingFileSystemAdapter& operator=(MappingFileSystemAdapter&&) MIJIN_NOEXCEPT = default; fs::path getHomeFolder() override; std::vector listFiles(const fs::path& folder) override; FileInfo getFileInfo(const fs::path& file) override; Optional getNativePath(const fs::path& file) override; StreamError open(const fs::path& path, FileOpenMode mode, std::unique_ptr& outStream) override; private: bool adjustPath(fs::path& path) const MIJIN_NOEXCEPT; }; // // public functions // template fs::path MappingFileSystemAdapter::getHomeFolder() { return "/"; } template std::vector MappingFileSystemAdapter::listFiles(const fs::path& folder) { fs::path adjusted = folder; if (!adjustPath(adjusted)) { return {}; } std::vector result; result = wrapped_.listFiles(adjusted); for (FileInfo& fileInfo : result) { if (fileInfo.path.is_absolute()) { fileInfo.path = fs::relative(fileInfo.path, "/"); } fileInfo.path = root_ / fileInfo.path; } return result; } template FileInfo MappingFileSystemAdapter::getFileInfo(const fs::path& file) { fs::path adjusted = file; if (!adjustPath(adjusted)) { return {}; } return wrapped_.getFileInfo(adjusted); } template Optional MappingFileSystemAdapter::getNativePath(const fs::path& file) { fs::path adjusted = file; if (!adjustPath(adjusted)) { return {}; } return wrapped_.getNativePath(adjusted); } template StreamError MappingFileSystemAdapter::open(const fs::path& path, FileOpenMode mode, std::unique_ptr& outStream) { fs::path adjusted = path; if (!adjustPath(adjusted)) { return {}; } return wrapped_.open(adjusted, mode, outStream); } template bool MappingFileSystemAdapter::adjustPath(fs::path& path) const MIJIN_NOEXCEPT { if (path.empty() || *path.generic_string().c_str() != '/') { return false; } // checks whether path starts with root auto [itRoot, itPath] = std::mismatch(root_.begin(), root_.end(), path.begin(), path.end()); if (itRoot != root_.end()) { return false; } std::error_code error; fs::path wrapped = fs::relative(path, root_, error); if (wrapped.empty() || error) { return false; } path = std::move(wrapped); return true; } namespace vfs_pipe { template struct MappingBuilder : Builder, MappingFileSystemAdapter> { fs::path root; TBase base; std::unique_ptr> build() { return std::make_unique>(root, std::move(*base.build())); } }; struct MappingOptions { fs::path root; }; [[nodiscard]] inline MappingOptions map_to(fs::path root) noexcept { return {.root = std::move(root) }; } template [[nodiscard]] MappingBuilder operator|(TBase other, MappingOptions options) noexcept { return {.root = std::move(options.root), .base = std::move(other) }; } } } // namespace mijin #endif // !defined(MIJIN_VIRTUAL_FILESYSTEM_MAPPING_HPP_INCLUDED)