Skip to content

Commit cf6bca4

Browse files
authored
Merge pull request #82 from bboczula/codex/issue-41-blob-lifecycle
[codex] Implement blob lifecycle storage
2 parents a74b1fc + 4e3ece5 commit cf6bca4

13 files changed

Lines changed: 700 additions & 4 deletions

include/AssetSuite/AssetSuite.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,31 @@ namespace AssetSuite
3737
LoggingCallback callback,
3838
LogLevel minLevel,
3939
void* userData);
40+
41+
// Loads a file into a runtime-owned blob. outBlob must point to a null
42+
// handle and receives ownership of the created blob handle on success.
43+
//
44+
// The blob bytes and source metadata are owned by the context. The caller
45+
// retains ownership of filePath and may release or mutate that string after
46+
// the call returns. A returned blob remains valid until ReleaseBlob is
47+
// called for the same context, or until the owning context is destroyed.
48+
// Blob operations follow the context's external synchronization
49+
// requirements.
50+
//
51+
// Passing a null context returns Result::ErrorInvalidContext. Passing a
52+
// null filePath, null outBlob, or non-null *outBlob returns
53+
// Result::ErrorInvalidArgument. Missing files return
54+
// Result::ErrorFileNotFound.
55+
ASSET_SUITE_API Result LoadFile(ContextHandle context, const char* filePath, BlobHandle* outBlob);
56+
57+
// Releases a runtime-owned blob and sets the caller's handle to nullptr on
58+
// success. Memory and metadata behind the blob are invalid immediately
59+
// after a successful release.
60+
//
61+
// The blob must have been created by LoadFile on the same context. Passing
62+
// a null context returns Result::ErrorInvalidContext. Passing nullptr, a
63+
// pointer to a null blob handle, a stale handle, or a handle from another
64+
// context returns Result::ErrorInvalidHandle. On failure, the caller's blob
65+
// value is preserved.
66+
ASSET_SUITE_API Result ReleaseBlob(ContextHandle context, BlobHandle* blob);
4067
}

include/AssetSuite/AssetSuiteDescriptors.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,14 @@ namespace AssetSuite
1616

1717
struct BlobDesc
1818
{
19+
// Must be exactly sizeof(BlobDesc) when a descriptor is supplied.
1920
uint32_t structSize;
21+
// Number of bytes owned by the blob.
2022
uint64_t byteSize;
23+
// Best-known asset format. May be Unknown when the source extension or
24+
// signature does not identify a supported asset type.
2125
AssetFormat format;
26+
// Reserved for future use. Must be zero.
2227
uint32_t flags;
2328
};
2429

include/AssetSuite/AssetSuiteTypes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ namespace AssetSuite
1818
ErrorOutputBufferTooSmall = -5,
1919
ErrorOutOfMemory = -6,
2020
ErrorInvalidContext = -7,
21+
ErrorInvalidHandle = -8,
2122
ErrorUnknown = -1000
2223
};
2324

source/common/AssetSuite.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,19 @@ namespace
4141
normalizedDesc = *desc;
4242
return AssetSuite::Result::Success;
4343
}
44+
45+
AssetSuite::Result MapFileLoadResult(AssetSuite::ErrorCode error)
46+
{
47+
switch (error)
48+
{
49+
case AssetSuite::ErrorCode::OK:
50+
return AssetSuite::Result::Success;
51+
case AssetSuite::ErrorCode::NonExistingFile:
52+
return AssetSuite::Result::ErrorFileNotFound;
53+
default:
54+
return AssetSuite::Result::ErrorUnknown;
55+
}
56+
}
4457
}
4558

4659
AssetSuite::Result AssetSuite::GetVersion(Version* outVersion)
@@ -76,6 +89,8 @@ const char* AssetSuite::GetResultString(Result result)
7689
return "Error: out of memory";
7790
case Result::ErrorInvalidContext:
7891
return "Error: invalid context";
92+
case Result::ErrorInvalidHandle:
93+
return "Error: invalid handle";
7994
case Result::ErrorUnknown:
8095
return "Error: unknown";
8196
default:
@@ -125,6 +140,59 @@ AssetSuite::Result AssetSuite::SetLoggingCallback(
125140
return Result::Success;
126141
}
127142

143+
AssetSuite::Result AssetSuite::LoadFile(ContextHandle context, const char* filePath, BlobHandle* outBlob)
144+
{
145+
if (!context)
146+
{
147+
return Result::ErrorInvalidContext;
148+
}
149+
150+
if (!filePath || !outBlob || *outBlob)
151+
{
152+
return Result::ErrorInvalidArgument;
153+
}
154+
155+
std::vector<uint8_t> rawBytes;
156+
const ErrorCode loadResult = context->Runtime().FileLoader().LoadToMemory(filePath, true, rawBytes);
157+
const Result mappedResult = MapFileLoadResult(loadResult);
158+
if (mappedResult != Result::Success)
159+
{
160+
context->Runtime().Diagnostics().Add(loadResult, "Failed to load blob source file.");
161+
return mappedResult;
162+
}
163+
164+
try
165+
{
166+
Internal::Blob blob(std::move(rawBytes), Internal::MakeBlobSourceMetadata(filePath));
167+
*outBlob = context->Runtime().BlobStorage().Create(std::move(blob));
168+
}
169+
catch (const std::bad_alloc&)
170+
{
171+
return Result::ErrorOutOfMemory;
172+
}
173+
catch (...)
174+
{
175+
return Result::ErrorUnknown;
176+
}
177+
178+
return Result::Success;
179+
}
180+
181+
AssetSuite::Result AssetSuite::ReleaseBlob(ContextHandle context, BlobHandle* blob)
182+
{
183+
if (!context)
184+
{
185+
return Result::ErrorInvalidContext;
186+
}
187+
188+
if (!blob || !*blob)
189+
{
190+
return Result::ErrorInvalidHandle;
191+
}
192+
193+
return context->Runtime().BlobStorage().Release(blob);
194+
}
195+
128196
AssetSuite::Manager::Manager()
129197
: runtimeState(new Internal::RuntimeState())
130198
, ownsRuntimeState(true)

source/runtime/AssetSuiteBlob.cpp

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#include "AssetSuiteBlob.h"
2+
3+
#include <algorithm>
4+
#include <cctype>
5+
#include <string>
6+
#include <utility>
7+
8+
namespace
9+
{
10+
AssetSuite::AssetFormat ResolveBlobFormat(const std::filesystem::path& extension) noexcept
11+
{
12+
std::string normalizedExtension = extension.string();
13+
std::transform(
14+
normalizedExtension.begin(),
15+
normalizedExtension.end(),
16+
normalizedExtension.begin(),
17+
[](unsigned char character)
18+
{
19+
return static_cast<char>(std::tolower(character));
20+
});
21+
22+
if (normalizedExtension == ".bmp")
23+
{
24+
return AssetSuite::AssetFormat::BMP;
25+
}
26+
27+
if (normalizedExtension == ".png")
28+
{
29+
return AssetSuite::AssetFormat::PNG;
30+
}
31+
32+
if (normalizedExtension == ".ppm")
33+
{
34+
return AssetSuite::AssetFormat::PPM;
35+
}
36+
37+
if (normalizedExtension == ".obj")
38+
{
39+
return AssetSuite::AssetFormat::WavefrontObj;
40+
}
41+
42+
return AssetSuite::AssetFormat::Unknown;
43+
}
44+
}
45+
46+
AssetSuite::Internal::Blob::Blob(std::vector<uint8_t> bytes, BlobSourceMetadata metadata)
47+
: bytes(std::move(bytes))
48+
, metadata(std::move(metadata))
49+
{
50+
}
51+
52+
AssetSuite::Internal::Blob::Blob(Blob&&) noexcept = default;
53+
54+
AssetSuite::Internal::Blob& AssetSuite::Internal::Blob::operator=(Blob&&) noexcept = default;
55+
56+
const uint8_t* AssetSuite::Internal::Blob::Data() const noexcept
57+
{
58+
return bytes.empty() ? nullptr : bytes.data();
59+
}
60+
61+
uint64_t AssetSuite::Internal::Blob::ByteSize() const noexcept
62+
{
63+
return static_cast<uint64_t>(bytes.size());
64+
}
65+
66+
const AssetSuite::Internal::BlobSourceMetadata&
67+
AssetSuite::Internal::Blob::SourceMetadata() const noexcept
68+
{
69+
return metadata;
70+
}
71+
72+
AssetSuite::BlobDesc AssetSuite::Internal::Blob::Describe() const noexcept
73+
{
74+
return BlobDesc
75+
{
76+
sizeof(BlobDesc),
77+
ByteSize(),
78+
metadata.format,
79+
0
80+
};
81+
}
82+
83+
AssetSuite::Internal::BlobSourceMetadata
84+
AssetSuite::Internal::MakeBlobSourceMetadata(const std::filesystem::path& sourcePath)
85+
{
86+
BlobSourceMetadata metadata = {};
87+
metadata.sourcePath = sourcePath;
88+
metadata.extension = sourcePath.extension();
89+
metadata.format = ResolveBlobFormat(metadata.extension);
90+
return metadata;
91+
}

source/runtime/AssetSuiteBlob.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#pragma once
2+
3+
#include <AssetSuite/AssetSuiteDescriptors.h>
4+
#include <AssetSuite/AssetSuiteHandles.h>
5+
#include <AssetSuite/AssetSuiteTypes.h>
6+
7+
#include <cstdint>
8+
#include <filesystem>
9+
#include <vector>
10+
11+
namespace AssetSuite::Internal
12+
{
13+
struct BlobSourceMetadata final
14+
{
15+
std::filesystem::path sourcePath;
16+
std::filesystem::path extension;
17+
AssetFormat format = AssetFormat::Unknown;
18+
};
19+
20+
class Blob final
21+
{
22+
public:
23+
Blob(std::vector<uint8_t> bytes, BlobSourceMetadata metadata);
24+
25+
Blob(const Blob&) = delete;
26+
Blob& operator=(const Blob&) = delete;
27+
Blob(Blob&&) noexcept;
28+
Blob& operator=(Blob&&) noexcept;
29+
30+
const uint8_t* Data() const noexcept;
31+
uint64_t ByteSize() const noexcept;
32+
const BlobSourceMetadata& SourceMetadata() const noexcept;
33+
BlobDesc Describe() const noexcept;
34+
35+
private:
36+
std::vector<uint8_t> bytes;
37+
BlobSourceMetadata metadata;
38+
};
39+
40+
BlobSourceMetadata MakeBlobSourceMetadata(const std::filesystem::path& sourcePath);
41+
}
42+
43+
namespace AssetSuite
44+
{
45+
struct AssetSuiteBlob_t
46+
{
47+
};
48+
}

source/runtime/AssetSuiteRuntime.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,18 @@ AssetSuite::Internal::RuntimeContext::FileLoader() noexcept
4949
return state.fileLoader;
5050
}
5151

52+
AssetSuite::Internal::RuntimeState::BlobStorage&
53+
AssetSuite::Internal::RuntimeContext::BlobStorage() noexcept
54+
{
55+
return state.blobStorage;
56+
}
57+
58+
const AssetSuite::Internal::RuntimeState::BlobStorage&
59+
AssetSuite::Internal::RuntimeContext::BlobStorage() const noexcept
60+
{
61+
return state.blobStorage;
62+
}
63+
5264
AssetSuite::Internal::RuntimeState::CodecRegistry&
5365
AssetSuite::Internal::RuntimeContext::CodecRegistry() noexcept
5466
{

source/runtime/AssetSuiteRuntime.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ namespace AssetSuite::Internal
2323
RuntimeState::Diagnostics& Diagnostics() noexcept;
2424
const RuntimeState::Diagnostics& Diagnostics() const noexcept;
2525
RuntimeState::FileLoader& FileLoader() noexcept;
26+
RuntimeState::BlobStorage& BlobStorage() noexcept;
27+
const RuntimeState::BlobStorage& BlobStorage() const noexcept;
2628
RuntimeState::CodecRegistry& CodecRegistry() noexcept;
2729
const RuntimeState::CodecRegistry& CodecRegistry() const noexcept;
2830

0 commit comments

Comments
 (0)