diff --git a/source/mijin/virtual_filesystem/filesystem.cpp b/source/mijin/virtual_filesystem/filesystem.cpp index 21651aa..e3060a3 100644 --- a/source/mijin/virtual_filesystem/filesystem.cpp +++ b/source/mijin/virtual_filesystem/filesystem.cpp @@ -30,13 +30,6 @@ namespace mijin // public functions // -std::vector OSFileSystemAdapter::getRoots() -{ - return { - "/" // TODO: other OSs - }; -} - fs::path OSFileSystemAdapter::getHomeFolder() { return getKnownFolder(KnownFolder::USER_HOME); diff --git a/source/mijin/virtual_filesystem/filesystem.hpp b/source/mijin/virtual_filesystem/filesystem.hpp index 7ea4e62..47aa2b1 100644 --- a/source/mijin/virtual_filesystem/filesystem.hpp +++ b/source/mijin/virtual_filesystem/filesystem.hpp @@ -79,7 +79,6 @@ class FileSystemAdapter public: virtual ~FileSystemAdapter() = default; - [[nodiscard]] virtual std::vector getRoots() = 0; [[nodiscard]] virtual fs::path getHomeFolder() = 0; [[nodiscard]] virtual std::vector listFiles(const fs::path& folder) = 0; [[nodiscard]] virtual FileInfo getFileInfo(const fs::path& file) = 0; @@ -92,7 +91,6 @@ public: class OSFileSystemAdapter : public FileSystemAdapter { public: - std::vector getRoots() override; fs::path getHomeFolder() override; std::vector listFiles(const fs::path& folder) override; FileInfo getFileInfo(const fs::path& file) override; @@ -153,6 +151,30 @@ inline std::string formatFileSize(std::size_t sizeInBytes) return oss.str(); } +namespace vfs_pipe +{ +template +struct Builder +{ + using adapter_t = TAdapter; + + operator std::unique_ptr() + { + return static_cast(*this).build(); + } +}; + +struct OSBuilder : Builder +{ + std::unique_ptr build() + { + return std::make_unique(); + } +}; + +[[nodiscard]] +inline OSBuilder os() noexcept { return {}; } +} } // namespace mijin template<> diff --git a/source/mijin/virtual_filesystem/mapping.hpp b/source/mijin/virtual_filesystem/mapping.hpp new file mode 100644 index 0000000..8064ee8 --- /dev/null +++ b/source/mijin/virtual_filesystem/mapping.hpp @@ -0,0 +1,175 @@ + +#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) + { + 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.is_absolute()) + { + 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) diff --git a/source/mijin/virtual_filesystem/relative.hpp b/source/mijin/virtual_filesystem/relative.hpp index b7a10ea..5a024db 100644 --- a/source/mijin/virtual_filesystem/relative.hpp +++ b/source/mijin/virtual_filesystem/relative.hpp @@ -38,7 +38,6 @@ public: RelativeFileSystemAdapter& operator=(const RelativeFileSystemAdapter&) = default; RelativeFileSystemAdapter& operator=(RelativeFileSystemAdapter&&) MIJIN_NOEXCEPT = default; - std::vector getRoots() override; fs::path getHomeFolder() override; std::vector listFiles(const fs::path& folder) override; FileInfo getFileInfo(const fs::path& file) override; @@ -52,12 +51,6 @@ private: // public functions // -template -std::vector RelativeFileSystemAdapter::getRoots() -{ - return { root_ }; -} - template fs::path RelativeFileSystemAdapter::getHomeFolder() { @@ -106,6 +99,39 @@ fs::path RelativeFileSystemAdapter::appendPath(const fs::path& other) } return combinedPath; } + +namespace vfs_pipe +{ +template +struct RelativeBuilder : Builder, RelativeFileSystemAdapter> +{ + fs::path root; + TBase base; + + std::unique_ptr> build() + { + return std::make_unique>(root, std::move(*base.build())); + } +}; + +struct RelativeOptions +{ + fs::path root; +}; + +[[nodiscard]] +inline RelativeOptions relative_to(fs::path root) noexcept +{ + return {.root = std::move(root) }; +} + +template +[[nodiscard]] +RelativeBuilder operator|(TBase other, RelativeOptions options) noexcept +{ + return {.root = std::move(options.root), .base = std::move(other) }; +} +} } // namespace mijin #endif // !defined(MIJIN_VIRTUAL_FILESYSTEM_RELATIVE_HPP_INCLUDED) diff --git a/source/mijin/virtual_filesystem/stacked.cpp b/source/mijin/virtual_filesystem/stacked.cpp index b588433..7f61624 100644 --- a/source/mijin/virtual_filesystem/stacked.cpp +++ b/source/mijin/virtual_filesystem/stacked.cpp @@ -30,24 +30,6 @@ namespace mijin // public functions // -std::vector StackedFileSystemAdapter::getRoots() -{ - std::vector roots; - - for (auto& adapter : adapters_) - { - for (const fs::path& root : adapter->getRoots()) - { - auto it = std::find(roots.begin(), roots.end(), root); - if (it == roots.end()) { - roots.push_back(root); - } - } - } - - return roots; -} - fs::path StackedFileSystemAdapter::getHomeFolder() { if (adapters_.empty()) { @@ -105,13 +87,28 @@ Optional StackedFileSystemAdapter::getNativePath(const fs::path& file) StreamError StackedFileSystemAdapter::open(const fs::path& path, FileOpenMode mode, std::unique_ptr& outStream) { + // try to open existing files first for (auto& adapter : adapters_) { const FileInfo fileInfo = adapter->getFileInfo(path); - if (fileInfo.exists) { + if (fileInfo.exists) + { return adapter->open(path, mode, outStream); } } + + // if that doesn't work we attempt to write, try creating it + if (mode == FileOpenMode::WRITE || mode == FileOpenMode::READ_WRITE) + { + for (auto& adapter : adapters_) + { + const StreamError error = adapter->open(path, mode, outStream); + if (error == StreamError::SUCCESS) + { + return StreamError::SUCCESS; + } + } + } return StreamError::IO_ERROR; } diff --git a/source/mijin/virtual_filesystem/stacked.hpp b/source/mijin/virtual_filesystem/stacked.hpp index 6f38f9f..725c5dc 100644 --- a/source/mijin/virtual_filesystem/stacked.hpp +++ b/source/mijin/virtual_filesystem/stacked.hpp @@ -28,7 +28,6 @@ class StackedFileSystemAdapter : public FileSystemAdapter private: std::vector> adapters_; public: - std::vector getRoots() override; fs::path getHomeFolder() override; std::vector listFiles(const fs::path& folder) override; FileInfo getFileInfo(const fs::path& file) override;