mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 00:32:45 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			93 lines
		
	
	
	
		
			2.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			93 lines
		
	
	
	
		
			2.9 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]] 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);
 | |
|     });
 | |
| }
 | |
| 
 | |
| }
 | 
