#pragma once #if !defined(MIJIN_VIRTUAL_FILESYSTEM_FILESYSTEM_HPP_INCLUDED) #define MIJIN_VIRTUAL_FILESYSTEM_FILESYSTEM_HPP_INCLUDED 1 #include #include #include #include #include #include #include "../io/stream.hpp" namespace fs = std::filesystem; namespace mijin { // // public defines // // // public constants // // // public types // struct FileInfo { fs::path path; std::size_t size = 0; bool exists : 1 = false; bool isFolder : 1 = false; bool isSymlink : 1 = false; bool isSpecial : 1 = false; bool isHidden : 1 = false; }; // basically just a thin wrapper around adapter + path, for utility class PathReference { private: class FileSystemAdapter* adapter_; fs::path path_; public: PathReference(class FileSystemAdapter* adapter, fs::path path) noexcept : adapter_(adapter), path_(std::move(path)) {} [[nodiscard]] class FileSystemAdapter* getAdapter() const noexcept { return adapter_; } [[nodiscard]] const fs::path& getPath() const noexcept { return path_; } [[nodiscard]] inline FileInfo getInfo() const; [[nodiscard]] inline StreamError open(FileOpenMode mode, std::unique_ptr& outStream) const; }; 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; [[nodiscard]] virtual StreamError open(const fs::path& path, FileOpenMode mode, std::unique_ptr& outStream) = 0; [[nodiscard]] PathReference getPath(fs::path path) noexcept { return PathReference(this, std::move(path)); } }; 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; StreamError open(const fs::path& path, FileOpenMode mode, std::unique_ptr& outStream) override; static OSFileSystemAdapter& getInstance(); }; // // public functions // inline FileInfo PathReference::getInfo() const { return adapter_->getFileInfo(path_); } inline StreamError PathReference::open(FileOpenMode mode, std::unique_ptr& outStream) const { return adapter_->open(path_, mode, outStream); } inline std::string formatFileType(const FileInfo& info) { if (info.isFolder) { return "Folder"; } if (info.isSpecial) { return "Special"; } return "File"; } inline std::string formatFileSize(std::size_t sizeInBytes) { static constexpr std::array suffixes = {"bytes", "KiB", "MiB", "GiB", "TiB"}; // enough? if (sizeInBytes == 0) { return "0 bytes"; } const std::size_t pos = std::min(static_cast(std::ceil(std::log2(sizeInBytes))) / 10, suffixes.size() - 1); std::stringstream oss; oss << std::setprecision(2) << std::fixed; if (pos == 0) { oss << sizeInBytes << " bytes"; } else { const float converted = static_cast(sizeInBytes) / std::pow(2.f, 10.f * static_cast(pos)); oss << converted << " " << suffixes[pos]; } return oss.str(); } } // namespace mijin #endif // !defined(MIJIN_VIRTUAL_FILESYSTEM_FILESYSTEM_HPP_INCLUDED)