Graphics/PipelinePassListLoader: Replace Result by exception to improve readability

This commit is contained in:
SirLynix 2023-11-06 19:14:23 +01:00 committed by Jérôme Leclercq
parent 886991f86d
commit 578240cd6f
1 changed files with 118 additions and 227 deletions

View File

@ -21,154 +21,107 @@ namespace Nz::Loaders
Result<std::shared_ptr<PipelinePassList>, ResourceLoadingError> Parse() Result<std::shared_ptr<PipelinePassList>, ResourceLoadingError> Parse()
{ {
auto result = ExpectKeyword("passlist"); try
if (!result)
return Err(std::move(result).GetError()); //< FIXME: why rvalue is needed
Result<std::string, ResourceLoadingError> passListName = GetString();
if (!passListName)
return Err(std::move(passListName).GetError()); //< FIXME: why rvalue is needed
m_current.emplace();
m_current->passList = std::make_shared<PipelinePassList>();
result = Block([this]() -> Result<void, ResourceLoadingError>
{ {
Result<std::string, ResourceLoadingError> kw = GetKeyword(); ExpectKeyword("passlist");
if (!kw)
return Err(std::move(kw).GetError()); //< FIXME: why rvalue is needed
if (kw.GetValue() == "attachment") std::string passListName = ReadString();
{
auto result = HandleAttachment();
if (!result)
return Err(std::move(result).GetError()); //< FIXME: why rvalue is needed
}
else if (kw.GetValue() == "pass")
{
auto result = HandlePass();
if (!result)
return Err(std::move(result).GetError()); //< FIXME: why rvalue is needed
}
else if (kw.GetValue() == "output")
{
Result<std::string, ResourceLoadingError> attachmentName = GetString();
if (!attachmentName)
return Err(std::move(attachmentName).GetError()); //< FIXME: why rvalue is needed
auto it = m_current->attachmentsByName.find(attachmentName.GetValue()); m_current.emplace();
if (it == m_current->attachmentsByName.end()) m_current->passList = std::make_shared<PipelinePassList>();
Block([this]
{
std::string kw = ReadKeyword();
if (kw == "attachment")
HandleAttachment();
else if (kw == "pass")
HandlePass();
else if (kw == "output")
{ {
NazaraErrorFmt("unknown attachment {}", attachmentName.GetValue()); std::string attachmentName = ReadString();
return Err(ResourceLoadingError::DecodingError);
auto it = m_current->attachmentsByName.find(attachmentName);
if (it == m_current->attachmentsByName.end())
{
NazaraErrorFmt("unknown attachment {}", attachmentName);
throw ResourceLoadingError::DecodingError;
}
m_current->passList->SetFinalOutput(it->second);
} }
else
{
NazaraErrorFmt("unexpected keyword {}", kw);
throw ResourceLoadingError::DecodingError;
}
});
m_current->passList->SetFinalOutput(it->second); return Ok(std::move(m_current->passList));
} }
else catch (ResourceLoadingError error)
{ {
NazaraErrorFmt("unexpected keyword {}", kw.GetValue()); return Err(error);
return Err(ResourceLoadingError::DecodingError); }
}
return Ok();
});
if (!result)
return Err(std::move(result).GetError()); //< FIXME: why rvalue is needed
return Ok(std::move(m_current->passList));
} }
private: private:
Result<void, ResourceLoadingError> Block(const FunctionRef<Result<void, ResourceLoadingError>()>& callback) void Block(const FunctionRef<void()>& callback)
{ {
auto beginBlock = GetKeyword(); std::string beginToken = ReadKeyword();
if (!beginBlock) if (beginToken != "{")
return Err(std::move(beginBlock).GetError()); //< FIXME: why rvalue is needed
if (beginBlock.GetValue() != "{")
{ {
NazaraErrorFmt("expected \"{{\" token, got {}", beginBlock.GetValue()); NazaraErrorFmt("expected \"{{\" token, got {}", beginToken);
return Err(ResourceLoadingError::DecodingError); throw ResourceLoadingError::DecodingError;
} }
for (;;) for (;;)
{ {
auto nextKw = GetKeyword(true); std::string nextKeyword = ReadKeyword(true);
if (!nextKw) if (nextKeyword == "}")
return Err(std::move(nextKw).GetError()); //< FIXME: why rvalue is needed
if (nextKw.GetValue() == "}")
break; break;
auto result = callback(); callback();
if (!result)
return Err(std::move(result).GetError()); //< FIXME: why rvalue is needed
} }
auto endBlock = GetKeyword(); std::string endToken = ReadKeyword();
if (!endBlock) if (endToken != "}")
return Err(std::move(endBlock).GetError()); //< FIXME: why rvalue is needed
if (endBlock.GetValue() != "}")
{ {
NazaraErrorFmt("expected \"}}\" token, got {}", endBlock.GetValue()); NazaraErrorFmt("expected \"}}\" token, got {}", endToken);
return Err(ResourceLoadingError::DecodingError); throw ResourceLoadingError::DecodingError;
} }
return Ok();
} }
Result<void, ResourceLoadingError> ExpectKeyword(std::string_view expectedKeyword) void ExpectKeyword(std::string_view expectedKeyword)
{ {
Result<std::string, ResourceLoadingError> passListKw = GetKeyword(); std::string keyword = ReadKeyword();
if (!passListKw) if (keyword != expectedKeyword)
return Err(std::move(passListKw).GetError()); //< FIXME: why rvalue is needed
if (passListKw.GetValue() != expectedKeyword)
{ {
NazaraErrorFmt("expected \"{}\" keyword, got {}", expectedKeyword, passListKw.GetValue()); NazaraErrorFmt("expected \"{}\" keyword, got {}", expectedKeyword, keyword);
return Err(ResourceLoadingError::DecodingError); throw ResourceLoadingError::DecodingError;
} }
return Ok();
} }
Result<void, ResourceLoadingError> HandleAttachment() void HandleAttachment()
{ {
Result<std::string, ResourceLoadingError> attachmentName = GetString(); std::string attachmentName = ReadString();
if (!attachmentName)
return Err(std::move(attachmentName).GetError()); //< FIXME: why rvalue is needed
std::string format; std::string format;
auto result = Block([&]() -> Result<void, ResourceLoadingError> Block([&]
{ {
Result<std::string, ResourceLoadingError> kw = GetKeyword(); std::string kw = ReadKeyword();
if (!kw) if (kw == "format")
return Err(std::move(kw).GetError()); //< FIXME: why rvalue is needed format = ReadString();
if (kw.GetValue() == "format")
{
Result<std::string, ResourceLoadingError> formatStr = GetString();
if (!formatStr)
return Err(std::move(formatStr).GetError()); //< FIXME: why rvalue is needed
format = std::move(formatStr).GetValue();
}
else else
{ {
NazaraErrorFmt("unexpected keyword {}", kw.GetValue()); NazaraErrorFmt("unexpected keyword {}", kw);
return Err(ResourceLoadingError::DecodingError); throw ResourceLoadingError::DecodingError;
} }
return Ok();
}); });
if (!result)
return Err(std::move(result).GetError()); //< FIXME: why rvalue is needed
if (format.empty()) if (format.empty())
{ {
NazaraErrorFmt("missing mandatory format in attachment {}", attachmentName.GetValue()); NazaraErrorFmt("missing mandatory format in attachment {}", attachmentName);
return Err(ResourceLoadingError::DecodingError); throw ResourceLoadingError::DecodingError;
} }
PixelFormat attachmentFormat = PixelFormat::Undefined; PixelFormat attachmentFormat = PixelFormat::Undefined;
@ -182,30 +135,26 @@ namespace Nz::Loaders
if (attachmentFormat == PixelFormat::Undefined) if (attachmentFormat == PixelFormat::Undefined)
{ {
NazaraErrorFmt("unknown format {}", format); NazaraErrorFmt("unknown format {}", format);
return Err(ResourceLoadingError::DecodingError); throw ResourceLoadingError::DecodingError;
} }
if (m_current->attachmentsByName.find(attachmentName.GetValue()) != m_current->attachmentsByName.end()) if (m_current->attachmentsByName.find(attachmentName) != m_current->attachmentsByName.end())
{ {
NazaraErrorFmt("attachment {} already exists", attachmentName.GetValue()); NazaraErrorFmt("attachment {} already exists", attachmentName);
return Err(ResourceLoadingError::DecodingError); throw ResourceLoadingError::DecodingError;
} }
std::size_t attachmentId = m_current->passList->AddAttachment({ std::size_t attachmentId = m_current->passList->AddAttachment({
attachmentName.GetValue(), attachmentName,
attachmentFormat attachmentFormat
}); });
m_current->attachmentsByName.emplace(attachmentName.GetValue(), attachmentId); m_current->attachmentsByName.emplace(attachmentName, attachmentId);
return Ok();
} }
Result<void, ResourceLoadingError> HandlePass() void HandlePass()
{ {
Result<std::string, ResourceLoadingError> passName = GetString(); std::string passName = ReadString();
if (!passName)
return Err(std::move(passName).GetError()); //< FIXME: why rvalue is needed
struct InputOutput struct InputOutput
{ {
@ -221,105 +170,58 @@ namespace Nz::Loaders
std::vector<InputOutput> outputs; std::vector<InputOutput> outputs;
std::vector<std::string> flags; std::vector<std::string> flags;
auto result = Block([&]() -> Result<void, ResourceLoadingError> Block([&]
{ {
Result<std::string, ResourceLoadingError> kw = GetKeyword(); std::string kw = ReadKeyword();
if (!kw)
return Err(std::move(kw).GetError()); //< FIXME: why rvalue is needed
if (kw.GetValue() == "impl") if (kw == "impl")
{ {
Result<std::string, ResourceLoadingError> implStr = GetString(); impl = ReadString();
if (!implStr)
return Err(std::move(implStr).GetError()); //< FIXME: why rvalue is needed
impl = std::move(implStr).GetValue(); std::string nextKeyword = ReadKeyword(true);
if (nextKeyword == "{")
auto nextKw = GetKeyword(true);
if (!nextKw)
return Err(std::move(nextKw).GetError()); //< FIXME: why rvalue is needed
if (nextKw.GetValue() == "{")
{ {
Block([&]() -> Result<void, ResourceLoadingError> Block([&]
{ {
Result<std::string, ResourceLoadingError> key = GetKeyword(); std::string key = ReadKeyword();
if (!key) std::string value = ReadString();
return Err(std::move(key).GetError()); //< FIXME: why rvalue is needed
Result<std::string, ResourceLoadingError> value = GetString(); implConfig.SetParameter(std::move(key), std::move(value));
if (!value)
return Err(std::move(value).GetError()); //< FIXME: why rvalue is needed
implConfig.SetParameter(key.GetValue(), value.GetValue());
return Ok();
}); });
} }
} }
else if (kw.GetValue() == "depthstencilinput") else if (kw == "depthstencilinput")
depthstencilInput = ReadString();
else if (kw == "depthstenciloutput")
depthstencilOutput = ReadString();
else if (kw == "flag")
flags.push_back(ReadString());
else if (kw == "input")
{ {
Result<std::string, ResourceLoadingError> attachmentStr = GetString(); std::string name = ReadString();
if (!attachmentStr) std::string attachment = ReadString();
return Err(std::move(attachmentStr).GetError()); //< FIXME: why rvalue is needed
depthstencilInput = std::move(attachmentStr).GetValue();
}
else if (kw.GetValue() == "depthstenciloutput")
{
Result<std::string, ResourceLoadingError> attachmentStr = GetString();
if (!attachmentStr)
return Err(std::move(attachmentStr).GetError()); //< FIXME: why rvalue is needed
depthstencilOutput = std::move(attachmentStr).GetValue();
}
else if (kw.GetValue() == "flag")
{
Result<std::string, ResourceLoadingError> str = GetString();
if (!str)
return Err(std::move(str).GetError()); //< FIXME: why rvalue is needed
flags.push_back(std::move(str).GetValue());
}
else if (kw.GetValue() == "input")
{
Result<std::string, ResourceLoadingError> name = GetString();
if (!name)
return Err(std::move(name).GetError()); //< FIXME: why rvalue is needed
Result<std::string, ResourceLoadingError> attachment = GetString();
if (!attachment)
return Err(std::move(attachment).GetError()); //< FIXME: why rvalue is needed
inputs.push_back({ inputs.push_back({
std::move(name).GetValue(), std::move(name),
std::move(attachment).GetValue(), std::move(attachment),
}); });
} }
else if (kw.GetValue() == "output") else if (kw == "output")
{ {
Result<std::string, ResourceLoadingError> name = GetString(); std::string name = ReadString();
if (!name) std::string attachment = ReadString();
return Err(std::move(name).GetError()); //< FIXME: why rvalue is needed
Result<std::string, ResourceLoadingError> attachment = GetString();
if (!attachment)
return Err(std::move(attachment).GetError()); //< FIXME: why rvalue is needed
outputs.push_back({ outputs.push_back({
std::move(name).GetValue(), std::move(name),
std::move(attachment).GetValue(), std::move(attachment),
}); });
} }
else else
{ {
NazaraErrorFmt("unexpected keyword {}", kw.GetValue()); NazaraErrorFmt("unexpected keyword {}", kw);
return Err(ResourceLoadingError::DecodingError); throw ResourceLoadingError::DecodingError;
} }
return Ok();
}); });
if (!result)
return Err(std::move(result).GetError()); //< FIXME: why rvalue is needed
FramePipelinePassRegistry& passRegistry = Graphics::Instance()->GetFramePipelinePassRegistry(); FramePipelinePassRegistry& passRegistry = Graphics::Instance()->GetFramePipelinePassRegistry();
@ -327,10 +229,10 @@ namespace Nz::Loaders
if (implIndex == FramePipelinePassRegistry::InvalidIndex) if (implIndex == FramePipelinePassRegistry::InvalidIndex)
{ {
NazaraErrorFmt("unknown pass {}", impl); NazaraErrorFmt("unknown pass {}", impl);
return Err(ResourceLoadingError::DecodingError); throw ResourceLoadingError::DecodingError;
} }
std::size_t passId = m_current->passList->AddPass(passName.GetValue(), implIndex, std::move(implConfig)); std::size_t passId = m_current->passList->AddPass(passName, implIndex, std::move(implConfig));
for (auto&& [inputName, attachmentName] : inputs) for (auto&& [inputName, attachmentName] : inputs)
{ {
@ -338,14 +240,14 @@ namespace Nz::Loaders
if (inputIndex == FramePipelinePassRegistry::InvalidIndex) if (inputIndex == FramePipelinePassRegistry::InvalidIndex)
{ {
NazaraErrorFmt("pass {} has no input {}", impl, inputName); NazaraErrorFmt("pass {} has no input {}", impl, inputName);
return Err(ResourceLoadingError::DecodingError); throw ResourceLoadingError::DecodingError;
} }
auto it = m_current->attachmentsByName.find(attachmentName); auto it = m_current->attachmentsByName.find(attachmentName);
if (it == m_current->attachmentsByName.end()) if (it == m_current->attachmentsByName.end())
{ {
NazaraErrorFmt("unknown attachment {}", attachmentName); NazaraErrorFmt("unknown attachment {}", attachmentName);
return Err(ResourceLoadingError::DecodingError); throw ResourceLoadingError::DecodingError;
} }
m_current->passList->SetPassInput(passId, inputIndex, it->second); m_current->passList->SetPassInput(passId, inputIndex, it->second);
@ -357,14 +259,14 @@ namespace Nz::Loaders
if (inputIndex == FramePipelinePassRegistry::InvalidIndex) if (inputIndex == FramePipelinePassRegistry::InvalidIndex)
{ {
NazaraErrorFmt("pass {} has no output {}", impl, outputName); NazaraErrorFmt("pass {} has no output {}", impl, outputName);
return Err(ResourceLoadingError::DecodingError); throw ResourceLoadingError::DecodingError;
} }
auto it = m_current->attachmentsByName.find(attachmentName); auto it = m_current->attachmentsByName.find(attachmentName);
if (it == m_current->attachmentsByName.end()) if (it == m_current->attachmentsByName.end())
{ {
NazaraErrorFmt("unknown attachment {}", attachmentName); NazaraErrorFmt("unknown attachment {}", attachmentName);
return Err(ResourceLoadingError::DecodingError); throw ResourceLoadingError::DecodingError;
} }
m_current->passList->SetPassOutput(passId, inputIndex, it->second); m_current->passList->SetPassOutput(passId, inputIndex, it->second);
@ -376,7 +278,7 @@ namespace Nz::Loaders
if (it == m_current->attachmentsByName.end()) if (it == m_current->attachmentsByName.end())
{ {
NazaraErrorFmt("unknown attachment {}", depthstencilInput); NazaraErrorFmt("unknown attachment {}", depthstencilInput);
return Err(ResourceLoadingError::DecodingError); throw ResourceLoadingError::DecodingError;
} }
m_current->passList->SetPassDepthStencilInput(passId, it->second); m_current->passList->SetPassDepthStencilInput(passId, it->second);
@ -388,7 +290,7 @@ namespace Nz::Loaders
if (it == m_current->attachmentsByName.end()) if (it == m_current->attachmentsByName.end())
{ {
NazaraErrorFmt("unknown attachment {}", depthstencilOutput); NazaraErrorFmt("unknown attachment {}", depthstencilOutput);
return Err(ResourceLoadingError::DecodingError); throw ResourceLoadingError::DecodingError;
} }
m_current->passList->SetPassDepthStencilOutput(passId, it->second); m_current->passList->SetPassDepthStencilOutput(passId, it->second);
@ -401,22 +303,17 @@ namespace Nz::Loaders
else else
{ {
NazaraErrorFmt("unknown pass flag {}", flagStr); NazaraErrorFmt("unknown pass flag {}", flagStr);
return Err(ResourceLoadingError::DecodingError); throw ResourceLoadingError::DecodingError;
} }
} }
return Ok();
} }
Result<std::string, ResourceLoadingError> GetKeyword(bool peek = false) std::string ReadKeyword(bool peek = false)
{ {
std::size_t beginOffset; std::size_t beginOffset;
do do
{ {
auto result = EnsureLine(); EnsureLine();
if (result.IsErr())
return Err(std::move(result).GetError()); //< FIXME: why rvalue is needed
beginOffset = m_currentLine.find_first_not_of(" \r\t\n"); beginOffset = m_currentLine.find_first_not_of(" \r\t\n");
} }
while (beginOffset == m_currentLine.npos); while (beginOffset == m_currentLine.npos);
@ -424,7 +321,7 @@ namespace Nz::Loaders
if (m_currentLine[beginOffset] == '"') if (m_currentLine[beginOffset] == '"')
{ {
NazaraError("expected a keyword, got a string"); NazaraError("expected a keyword, got a string");
return Err(ResourceLoadingError::DecodingError); throw ResourceLoadingError::DecodingError;
} }
std::size_t endOffset = m_currentLine.find_first_of(" \r\t\n", beginOffset + 1); std::size_t endOffset = m_currentLine.find_first_of(" \r\t\n", beginOffset + 1);
@ -438,16 +335,12 @@ namespace Nz::Loaders
return currentToken; return currentToken;
} }
std::string ReadString()
Result<std::string, ResourceLoadingError> GetString()
{ {
std::size_t beginOffset; std::size_t beginOffset;
do do
{ {
auto result = EnsureLine(); EnsureLine();
if (result.IsErr())
return Err(std::move(result).GetError()); //< FIXME: why rvalue is needed
beginOffset = m_currentLine.find_first_not_of(" \r\t\n"); beginOffset = m_currentLine.find_first_not_of(" \r\t\n");
} }
while (beginOffset == m_currentLine.npos); while (beginOffset == m_currentLine.npos);
@ -455,7 +348,7 @@ namespace Nz::Loaders
if (m_currentLine[beginOffset] != '"') if (m_currentLine[beginOffset] != '"')
{ {
NazaraError("expected a string, got a keyword"); NazaraError("expected a string, got a keyword");
return Err(ResourceLoadingError::DecodingError); throw ResourceLoadingError::DecodingError;
} }
std::string str; std::string str;
@ -467,7 +360,7 @@ namespace Nz::Loaders
case '\n': case '\n':
case '\r': case '\r':
NazaraError("unfinished string"); NazaraError("unfinished string");
return Err(ResourceLoadingError::DecodingError); throw ResourceLoadingError::DecodingError;
case '"': case '"':
{ {
@ -489,7 +382,7 @@ namespace Nz::Loaders
case '\\': character = '\\'; break; case '\\': character = '\\'; break;
default: default:
NazaraErrorFmt("unrecognized character {}", character); NazaraErrorFmt("unrecognized character {}", character);
return Err(ResourceLoadingError::DecodingError); throw ResourceLoadingError::DecodingError;
} }
str.push_back(character); str.push_back(character);
@ -502,20 +395,18 @@ namespace Nz::Loaders
} }
NazaraError("unfinished string"); NazaraError("unfinished string");
return Err(ResourceLoadingError::DecodingError); throw ResourceLoadingError::DecodingError;
} }
Result<void, ResourceLoadingError> EnsureLine() void EnsureLine()
{ {
while (m_currentLine.find_first_not_of(" \r\t\n") == m_currentLine.npos) while (m_currentLine.find_first_not_of(" \r\t\n") == m_currentLine.npos)
{ {
m_currentLine.clear(); m_currentLine.clear();
m_stream.ReadLine(m_currentLine); m_stream.ReadLine(m_currentLine);
if (m_currentLine.empty()) if (m_currentLine.empty())
return Err(ResourceLoadingError::DecodingError); throw ResourceLoadingError::DecodingError;
} }
return Ok();
} }
struct CurrentPassList struct CurrentPassList