ladybird/Userland/Libraries/LibCore/Resource.h
Shannon Booth 28307d0db6 LibCore: Add modified time to Resource
For now, all Resources are implemented with a modification time, but the
public API has been left as an Optional since abstractly, not all
resources will have a modification time.
2024-04-02 07:51:02 +02:00

96 lines
3.0 KiB
C++

/*
* Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/ByteBuffer.h>
#include <AK/Error.h>
#include <AK/MemoryStream.h>
#include <AK/RefPtr.h>
#include <AK/Span.h>
#include <AK/String.h>
#include <AK/StringView.h>
#include <AK/Variant.h>
#include <LibCore/File.h>
#include <LibCore/MappedFile.h>
namespace Core {
class Resource : public RefCounted<Resource> {
public:
static ErrorOr<NonnullRefPtr<Resource>> load_from_filesystem(StringView);
static ErrorOr<NonnullRefPtr<Resource>> load_from_uri(StringView);
[[nodiscard]] bool is_file() const { return !m_data.has<DirectoryTag>(); }
[[nodiscard]] bool is_directory() const { return m_data.has<DirectoryTag>(); }
[[nodiscard]] String uri() const;
[[nodiscard]] String filename() const;
[[nodiscard]] String filesystem_path() const;
[[nodiscard]] String file_url() const;
[[nodiscard]] Optional<time_t> modified_time() const;
[[nodiscard]] ByteBuffer clone_data() const;
[[nodiscard]] ByteBuffer release_data() &&;
[[nodiscard]] ReadonlyBytes data() const;
[[nodiscard]] FixedMemoryStream stream() const;
[[nodiscard]] Vector<String> children() const;
// Depth-first
template<IteratorFunction<Resource const&> Callback>
IterationDecision for_each_descendant(Callback&&) const;
template<IteratorFunction<Resource const&> Callback>
void for_each_descendant_file(Callback&&) const;
struct DirectoryTag { };
private:
friend class ResourceImplementation;
enum class Scheme {
File,
Resource,
};
Resource(String path, Scheme, NonnullOwnPtr<Core::MappedFile>, time_t modified_time);
Resource(String path, Scheme, ByteBuffer, time_t modified_time);
Resource(String path, Scheme, DirectoryTag, time_t modified_time);
String m_path; // Relative to scheme root. File: abspath, Resource: resource root
Scheme m_scheme;
Variant<DirectoryTag, NonnullOwnPtr<Core::MappedFile>, ByteBuffer> m_data;
time_t m_modified_time {};
};
template<IteratorFunction<Resource const&> Callback>
IterationDecision Resource::for_each_descendant(Callback&& callback) const
{
auto children = this->children();
for (auto const& child : children) {
if (auto child_resource = load_from_uri(MUST(String::formatted("{}/{}", uri(), child))); !child_resource.is_error()) {
if (callback(*child_resource.value()) == IterationDecision::Break)
return IterationDecision::Break;
if (child_resource.value()->for_each_descendant(callback) == IterationDecision::Break)
return IterationDecision::Break;
}
}
return IterationDecision::Continue;
}
template<IteratorFunction<Resource const&> Callback>
void Resource::for_each_descendant_file(Callback&& callback) const
{
for_each_descendant([callback = forward<Callback>(callback)](Resource const& resource) {
if (resource.is_directory())
return IterationDecision::Continue;
return callback(resource);
});
}
}