mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 01:17:35 +00:00
LibCore: Add Resource for platform agnostic application resource loading
The first implementation is simply raw files.
This commit is contained in:
parent
f4a89c31c6
commit
0d417cd604
8 changed files with 393 additions and 0 deletions
90
Userland/Libraries/LibCore/Resource.h
Normal file
90
Userland/Libraries/LibCore/Resource.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* 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_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]] Optional<String> filesystem_path() 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>);
|
||||
Resource(String path, Scheme, ByteBuffer);
|
||||
Resource(String path, Scheme, DirectoryTag);
|
||||
|
||||
String m_path; // Relative to scheme root. File: abspath, Resource: resource root
|
||||
Scheme m_scheme;
|
||||
|
||||
Variant<DirectoryTag, NonnullOwnPtr<Core::MappedFile>, ByteBuffer> m_data;
|
||||
};
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue