Pre Redesign

This commit is contained in:
2026-01-21 03:25:52 +05:30
parent 71fc7ae581
commit dedf28c6cb
58 changed files with 605 additions and 483 deletions

18
.clang-tidy Normal file
View File

@ -0,0 +1,18 @@
Checks: 'readability-identifier-naming'
CheckOptions:
- key: readability-identifier-naming.MethodCase
value: PascalCase
- key: readability-identifier-naming.StructMemberCase
value: lower_case
- key: readability-identifier-naming.PrivateMemberCase
value: camelCase
- key: readability-identifier-naming.PrivateMemberPrefix
value: m_
- key: readability-identifier-naming.ClassCase
value: PascalCase
- key: readability-identifier-naming.StructCase
value: PascalCase

View File

@ -1,3 +1,3 @@
Index:
PathExclude:
- .*/EmbeddedResources\.cpp
CompileFlags:
Add: [-Wno-missing-field-initializers, -Wno-missing-designated-field-initializers]

13
.vscode/launch.json vendored
View File

@ -3,24 +3,13 @@
"configurations": [
{
"name": "Debug (Linux)",
"type": "cppdbg",
"type": "lldb",
"request": "launch",
"program": "${command:cmake.launchTargetPath}",
"args": [
"dummy"
],
"stopAtEntry": false,
"cwd": "${workspaceFolder}/",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "CMake Build"
}
]

View File

@ -1,5 +1,9 @@
{
"editor.formatOnSave": true,
"C_Cpp.codeAnalysis.runAutomatically": "onSave",
"C_Cpp.codeAnalysis.clangTidy.enabled": true,
"C_Cpp.codeAnalysis.clangTidy.useBuildPath": false,
"C_Cpp.codeAnalysis.clangTidy.config": "",
"C_Cpp.clang_format_fallbackStyle": "Microsoft",
"cmake.copyCompileCommands": "${workspaceFolder}/compile_commands.json"
"cmake.copyCompileCommands": "${workspaceFolder}/compile_commands.json",
}

View File

@ -13,9 +13,12 @@ set(SRC_FILES
"imp/cpp/SocketOps.cpp"
"imp/cpp/StringOps.cpp"
"imp/cpp/ProcessOps.cpp"
"imp/cpp/HttpClient.cpp"
"imp/cpp/StreamReader.cpp"
"imp/cpp/StreamWriter.cpp"
"imp/cpp/Http/Common.cpp"
"imp/cpp/Http/Client.cpp"
"imp/cpp/Http/Server.cpp"
)
add_library(IACore STATIC ${SRC_FILES})

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -272,7 +272,7 @@ namespace IACore
return CompressionType::None;
}
Expected<Vector<UINT8>, String> DataOps::ZlibInflate(IN Span<CONST UINT8> data)
EXPECT(Vector<UINT8>) DataOps::ZlibInflate(IN Span<CONST UINT8> data)
{
z_stream zs{};
zs.zalloc = Z_NULL;
@ -323,7 +323,7 @@ namespace IACore
return outBuffer;
}
Expected<Vector<UINT8>, String> DataOps::ZlibDeflate(IN Span<CONST UINT8> data)
EXPECT(Vector<UINT8>) DataOps::ZlibDeflate(IN Span<CONST UINT8> data)
{
z_stream zs{};
zs.zalloc = Z_NULL;
@ -357,7 +357,7 @@ namespace IACore
return outBuffer;
}
Expected<Vector<UINT8>, String> DataOps::ZstdInflate(IN Span<CONST UINT8> data)
EXPECT(Vector<UINT8>) DataOps::ZstdInflate(IN Span<CONST UINT8> data)
{
unsigned long long const contentSize = ZSTD_getFrameContentSize(data.data(), data.size());
@ -412,7 +412,7 @@ namespace IACore
return outBuffer;
}
Expected<Vector<UINT8>, String> DataOps::ZstdDeflate(IN Span<CONST UINT8> data)
EXPECT(Vector<UINT8>) DataOps::ZstdDeflate(IN Span<CONST UINT8> data)
{
size_t const maxDstSize = ZSTD_compressBound(data.size());
@ -428,7 +428,7 @@ namespace IACore
return outBuffer;
}
Expected<Vector<UINT8>, String> DataOps::GZipDeflate(IN Span<CONST UINT8> data)
EXPECT(Vector<UINT8>) DataOps::GZipDeflate(IN Span<CONST UINT8> data)
{
z_stream zs{};
zs.zalloc = Z_NULL;
@ -465,7 +465,7 @@ namespace IACore
return outBuffer;
}
Expected<Vector<UINT8>, String> DataOps::GZipInflate(IN Span<CONST UINT8> data)
EXPECT(Vector<UINT8>) DataOps::GZipInflate(IN Span<CONST UINT8> data)
{
return ZlibInflate(data);
}

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -38,7 +38,7 @@ namespace IACore
#endif
}
Expected<PUINT8, String> FileOps::MapSharedMemory(IN CONST String &name, IN SIZE_T size, IN BOOL isOwner)
EXPECT(PUINT8) FileOps::MapSharedMemory(IN CONST String &name, IN SIZE_T size, IN BOOL isOwner)
{
#if IA_PLATFORM_WINDOWS
int wchars_num = MultiByteToWideChar(CP_UTF8, 0, name.c_str(), -1, NULL, 0);
@ -112,7 +112,7 @@ namespace IACore
#endif
}
Expected<PCUINT8, String> FileOps::MapFile(IN CONST FilePath &path, OUT SIZE_T &size)
EXPECT(PCUINT8) FileOps::MapFile(IN CONST FilePath &path, OUT SIZE_T &size)
{
#if IA_PLATFORM_WINDOWS
@ -182,21 +182,21 @@ namespace IACore
#endif
}
Expected<StreamWriter, String> FileOps::StreamToFile(IN CONST FilePath &path, IN BOOL overwrite)
EXPECT(StreamWriter) FileOps::StreamToFile(IN CONST FilePath &path, IN BOOL overwrite)
{
if (!overwrite && FileSystem::exists(path))
return MakeUnexpected(std::format("File aready exists: {}", path.string().c_str()));
return StreamWriter(path);
}
Expected<StreamReader, String> FileOps::StreamFromFile(IN CONST FilePath &path)
EXPECT(StreamReader) FileOps::StreamFromFile(IN CONST FilePath &path)
{
if (!FileSystem::exists(path))
return MakeUnexpected(std::format("File does not exist: {}", path.string().c_str()));
return StreamReader(path);
}
Expected<String, String> FileOps::ReadTextFile(IN CONST FilePath &path)
EXPECT(String) FileOps::ReadTextFile(IN CONST FilePath &path)
{
const auto f = fopen(path.string().c_str(), "r");
if (!f)
@ -210,7 +210,7 @@ namespace IACore
return result;
}
Expected<Vector<UINT8>, String> FileOps::ReadBinaryFile(IN CONST FilePath &path)
EXPECT(Vector<UINT8>) FileOps::ReadBinaryFile(IN CONST FilePath &path)
{
const auto f = fopen(path.string().c_str(), "rb");
if (!f)
@ -224,8 +224,7 @@ namespace IACore
return result;
}
Expected<SIZE_T, String> FileOps::WriteTextFile(IN CONST FilePath &path, IN CONST String &contents,
IN BOOL overwrite)
EXPECT(SIZE_T) FileOps::WriteTextFile(IN CONST FilePath &path, IN CONST String &contents, IN BOOL overwrite)
{
const char *mode = overwrite ? "w" : "wx";
const auto f = fopen(path.string().c_str(), mode);
@ -240,8 +239,7 @@ namespace IACore
return result;
}
Expected<SIZE_T, String> FileOps::WriteBinaryFile(IN CONST FilePath &path, IN Span<UINT8> contents,
IN BOOL overwrite)
EXPECT(SIZE_T) FileOps::WriteBinaryFile(IN CONST FilePath &path, IN Span<UINT8> contents, IN BOOL overwrite)
{
const char *mode = overwrite ? "w" : "wx";
const auto f = fopen(path.string().c_str(), mode);
@ -281,8 +279,8 @@ namespace IACore
namespace IACore
{
Expected<NativeFileHandle, String> FileOps::NativeOpenFile(IN CONST FilePath &path, IN EFileAccess access,
IN EFileMode mode, IN UINT32 permissions)
EXPECT(NativeFileHandle)
FileOps::NativeOpenFile(IN CONST FilePath &path, IN EFileAccess access, IN EFileMode mode, IN UINT32 permissions)
{
#if IA_PLATFORM_WINDOWS
DWORD dwAccess = 0;
@ -414,7 +412,7 @@ namespace IACore
return *this;
}
Expected<VOID, String> FileOps::MemoryMappedRegion::Map(NativeFileHandle handle, UINT64 offset, SIZE_T size)
EXPECT(VOID) FileOps::MemoryMappedRegion::Map(NativeFileHandle handle, UINT64 offset, SIZE_T size)
{
Unmap();

View File

@ -0,0 +1,139 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <IACore/Http/Client.hpp>
#include <IACore/DataOps.hpp>
namespace IACore
{
EXPECT(UniquePtr<HttpClient>) HttpClient::Create(IN CONST String &host)
{
return MakeUniqueProtected<HttpClient>(httplib::Client(host));
}
httplib::Headers BuildHeaders(IN Span<CONST HttpClient::Header> headers, IN PCCHAR defaultContentType)
{
httplib::Headers out;
bool hasContentType = false;
for (const auto &h : headers)
{
out.emplace(h.first, h.second);
if (h.first == HttpClient::HeaderTypeToString(HttpClient::EHeaderType::CONTENT_TYPE))
hasContentType = true;
}
if (!hasContentType && defaultContentType)
out.emplace("Content-Type", defaultContentType);
return out;
}
HttpClient::HttpClient(IN httplib::Client &&client)
: m_client(IA_MOVE(client)), m_lastResponseCode(EResponseCode::INTERNAL_SERVER_ERROR)
{
m_client.enable_server_certificate_verification(true);
}
HttpClient::~HttpClient()
{
}
VOID HttpClient::EnableCertificateVerfication()
{
m_client.enable_server_certificate_verification(true);
}
VOID HttpClient::DisableCertificateVerfication()
{
m_client.enable_server_certificate_verification(false);
}
String HttpClient::PreprocessResponse(IN CONST String &response)
{
const auto responseBytes = Span<CONST UINT8>{(PCUINT8) response.data(), response.size()};
const auto compression = DataOps::DetectCompression(responseBytes);
switch (compression)
{
case DataOps::CompressionType::Gzip: {
const auto data = DataOps::GZipInflate(responseBytes);
if (!data)
return response;
return String((PCCHAR) data->data(), data->size());
}
case DataOps::CompressionType::Zlib: {
const auto data = DataOps::ZlibInflate(responseBytes);
if (!data)
return response;
return String((PCCHAR) data->data(), data->size());
}
case DataOps::CompressionType::None:
default:
break;
}
return response;
}
EXPECT(String)
HttpClient::RawGet(IN CONST String &path, IN Span<CONST Header> headers, IN PCCHAR defaultContentType)
{
auto httpHeaders = BuildHeaders(headers, defaultContentType);
auto res = m_client.Get((!path.empty() && path[0] != '/') ? ('/' + path).c_str() : path.c_str(), httpHeaders);
if (res)
{
m_lastResponseCode = static_cast<EResponseCode>(res->status);
if (res->status >= 200 && res->status < 300)
return PreprocessResponse(res->body);
else
return MakeUnexpected(std::format("HTTP Error {} : {}", res->status, res->body));
}
return MakeUnexpected(std::format("Network Error: {}", httplib::to_string(res.error())));
}
EXPECT(String)
HttpClient::RawPost(IN CONST String &path, IN Span<CONST Header> headers, IN CONST String &body,
IN PCCHAR defaultContentType)
{
auto httpHeaders = BuildHeaders(headers, defaultContentType);
String contentType = defaultContentType;
if (httpHeaders.count("Content-Type"))
{
const auto t = httpHeaders.find("Content-Type");
contentType = t->second;
httpHeaders.erase(t);
}
m_client.set_keep_alive(true);
auto res = m_client.Post((!path.empty() && path[0] != '/') ? ('/' + path).c_str() : path.c_str(), httpHeaders,
body, contentType.c_str());
if (res)
{
m_lastResponseCode = static_cast<EResponseCode>(res->status);
if (res->status >= 200 && res->status < 300)
return PreprocessResponse(res->body);
else
return MakeUnexpected(std::format("HTTP Error {} : {}", res->status, res->body));
}
return MakeUnexpected(std::format("Network Error: {}", httplib::to_string(res.error())));
}
} // namespace IACore

View File

@ -0,0 +1,124 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <IACore/Http/Common.hpp>
namespace IACore
{
String HttpCommon::UrlEncode(IN CONST String &value)
{
std::stringstream escaped;
escaped.fill('0');
escaped << std::hex << std::uppercase;
for (char c : value)
{
if (std::isalnum(static_cast<unsigned char>(c)) || c == '-' || c == '_' || c == '.' || c == '~')
escaped << c;
else
escaped << '%' << std::setw(2) << static_cast<int>(static_cast<unsigned char>(c));
}
return escaped.str();
}
String HttpCommon::UrlDecode(IN CONST String &value)
{
String result;
result.reserve(value.length());
for (size_t i = 0; i < value.length(); ++i)
{
if (value[i] == '%' && i + 2 < value.length())
{
std::string hexStr = value.substr(i + 1, 2);
char decodedChar = static_cast<char>(std::strtol(hexStr.c_str(), nullptr, 16));
result += decodedChar;
i += 2;
}
else if (value[i] == '+')
result += ' ';
else
result += value[i];
}
return result;
}
String HttpCommon::HeaderTypeToString(IN EHeaderType type)
{
switch (type)
{
case EHeaderType::ACCEPT:
return "Accept";
case EHeaderType::ACCEPT_CHARSET:
return "Accept-Charset";
case EHeaderType::ACCEPT_ENCODING:
return "Accept-Encoding";
case EHeaderType::ACCEPT_LANGUAGE:
return "Accept-Language";
case EHeaderType::AUTHORIZATION:
return "Authorization";
case EHeaderType::CACHE_CONTROL:
return "Cache-Control";
case EHeaderType::CONNECTION:
return "Connection";
case EHeaderType::CONTENT_LENGTH:
return "Content-Length";
case EHeaderType::CONTENT_TYPE:
return "Content-Type";
case EHeaderType::COOKIE:
return "Cookie";
case EHeaderType::DATE:
return "Date";
case EHeaderType::EXPECT:
return "Expect";
case EHeaderType::HOST:
return "Host";
case EHeaderType::IF_MATCH:
return "If-Match";
case EHeaderType::IF_MODIFIED_SINCE:
return "If-Modified-Since";
case EHeaderType::IF_NONE_MATCH:
return "If-None-Match";
case EHeaderType::ORIGIN:
return "Origin";
case EHeaderType::PRAGMA:
return "Pragma";
case EHeaderType::PROXY_AUTHORIZATION:
return "Proxy-Authorization";
case EHeaderType::RANGE:
return "Range";
case EHeaderType::REFERER:
return "Referer";
case EHeaderType::TE:
return "TE";
case EHeaderType::UPGRADE:
return "Upgrade";
case EHeaderType::USER_AGENT:
return "User-Agent";
case EHeaderType::VIA:
return "Via";
case EHeaderType::WARNING:
return "Warning";
}
return "<Unknown>";
}
BOOL HttpCommon::IsSuccessResponseCode(IN EResponseCode code)
{
return (INT32) code >= 200 && (INT32) code < 300;
}
} // namespace IACore

View File

@ -0,0 +1,21 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <IACore/Http/Server.hpp>
namespace IACore
{
}

View File

@ -1,238 +0,0 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <IACore/HttpClient.hpp>
#include <IACore/DataOps.hpp>
#include <httplib.h>
namespace IACore
{
httplib::Headers BuildHeaders(IN Span<CONST HttpClient::Header> headers, IN PCCHAR defaultContentType)
{
httplib::Headers out;
bool hasContentType = false;
for (const auto &h : headers)
{
out.emplace(h.first, h.second);
if (h.first == HttpClient::HeaderTypeToString(HttpClient::EHeaderType::CONTENT_TYPE))
hasContentType = true;
}
if (!hasContentType && defaultContentType)
out.emplace("Content-Type", defaultContentType);
return out;
}
HttpClient::HttpClient(IN CONST String &host)
: m_client(new httplib::Client(host)), m_lastResponseCode(EResponseCode::INTERNAL_SERVER_ERROR)
{
}
HttpClient::~HttpClient()
{
if (m_client)
delete static_cast<httplib::Client *>(m_client);
}
String HttpClient::PreprocessResponse(IN CONST String &response)
{
const auto responseBytes = Span<CONST UINT8>{(PCUINT8) response.data(), response.size()};
const auto compression = DataOps::DetectCompression(responseBytes);
switch (compression)
{
case DataOps::CompressionType::Gzip: {
const auto data = DataOps::GZipInflate(responseBytes);
if (!data)
return response;
return String((PCCHAR) data->data(), data->size());
}
case DataOps::CompressionType::Zlib: {
const auto data = DataOps::ZlibInflate(responseBytes);
if (!data)
return response;
return String((PCCHAR) data->data(), data->size());
}
case DataOps::CompressionType::None:
default:
break;
}
return response;
}
Expected<String, String> HttpClient::RawGet(IN CONST String &path, IN Span<CONST Header> headers,
IN PCCHAR defaultContentType)
{
auto httpHeaders = BuildHeaders(headers, defaultContentType);
static_cast<httplib::Client *>(m_client)->enable_server_certificate_verification(false);
auto res = static_cast<httplib::Client *>(m_client)->Get(
(!path.empty() && path[0] != '/') ? ('/' + path).c_str() : path.c_str(), httpHeaders);
if (res)
{
m_lastResponseCode = static_cast<EResponseCode>(res->status);
if (res->status >= 200 && res->status < 300)
return PreprocessResponse(res->body);
else
return MakeUnexpected(std::format("HTTP Error {} : {}", res->status, res->body));
}
return MakeUnexpected(std::format("Network Error: {}", httplib::to_string(res.error())));
}
Expected<String, String> HttpClient::RawPost(IN CONST String &path, IN Span<CONST Header> headers,
IN CONST String &body, IN PCCHAR defaultContentType)
{
auto httpHeaders = BuildHeaders(headers, defaultContentType);
String contentType = defaultContentType;
if (httpHeaders.count("Content-Type"))
{
const auto t = httpHeaders.find("Content-Type");
contentType = t->second;
httpHeaders.erase(t);
}
static_cast<httplib::Client *>(m_client)->set_keep_alive(true);
static_cast<httplib::Client *>(m_client)->enable_server_certificate_verification(false);
auto res = static_cast<httplib::Client *>(m_client)->Post(
(!path.empty() && path[0] != '/') ? ('/' + path).c_str() : path.c_str(), httpHeaders, body,
contentType.c_str());
if (res)
{
m_lastResponseCode = static_cast<EResponseCode>(res->status);
if (res->status >= 200 && res->status < 300)
return PreprocessResponse(res->body);
else
return MakeUnexpected(std::format("HTTP Error {} : {}", res->status, res->body));
}
return MakeUnexpected(std::format("Network Error: {}", httplib::to_string(res.error())));
}
} // namespace IACore
namespace IACore
{
String HttpClient::UrlEncode(IN CONST String &value)
{
std::stringstream escaped;
escaped.fill('0');
escaped << std::hex << std::uppercase;
for (char c : value)
{
if (std::isalnum(static_cast<unsigned char>(c)) || c == '-' || c == '_' || c == '.' || c == '~')
escaped << c;
else
escaped << '%' << std::setw(2) << static_cast<int>(static_cast<unsigned char>(c));
}
return escaped.str();
}
String HttpClient::UrlDecode(IN CONST String &value)
{
String result;
result.reserve(value.length());
for (size_t i = 0; i < value.length(); ++i)
{
if (value[i] == '%' && i + 2 < value.length())
{
std::string hexStr = value.substr(i + 1, 2);
char decodedChar = static_cast<char>(std::strtol(hexStr.c_str(), nullptr, 16));
result += decodedChar;
i += 2;
}
else if (value[i] == '+')
result += ' ';
else
result += value[i];
}
return result;
}
String HttpClient::HeaderTypeToString(IN EHeaderType type)
{
switch (type)
{
case EHeaderType::ACCEPT:
return "Accept";
case EHeaderType::ACCEPT_CHARSET:
return "Accept-Charset";
case EHeaderType::ACCEPT_ENCODING:
return "Accept-Encoding";
case EHeaderType::ACCEPT_LANGUAGE:
return "Accept-Language";
case EHeaderType::AUTHORIZATION:
return "Authorization";
case EHeaderType::CACHE_CONTROL:
return "Cache-Control";
case EHeaderType::CONNECTION:
return "Connection";
case EHeaderType::CONTENT_LENGTH:
return "Content-Length";
case EHeaderType::CONTENT_TYPE:
return "Content-Type";
case EHeaderType::COOKIE:
return "Cookie";
case EHeaderType::DATE:
return "Date";
case EHeaderType::EXPECT:
return "Expect";
case EHeaderType::HOST:
return "Host";
case EHeaderType::IF_MATCH:
return "If-Match";
case EHeaderType::IF_MODIFIED_SINCE:
return "If-Modified-Since";
case EHeaderType::IF_NONE_MATCH:
return "If-None-Match";
case EHeaderType::ORIGIN:
return "Origin";
case EHeaderType::PRAGMA:
return "Pragma";
case EHeaderType::PROXY_AUTHORIZATION:
return "Proxy-Authorization";
case EHeaderType::RANGE:
return "Range";
case EHeaderType::REFERER:
return "Referer";
case EHeaderType::TE:
return "TE";
case EHeaderType::UPGRADE:
return "Upgrade";
case EHeaderType::USER_AGENT:
return "User-Agent";
case EHeaderType::VIA:
return "Via";
case EHeaderType::WARNING:
return "Warning";
}
return "<Unknown>";
}
BOOL HttpClient::IsSuccessResponseCode(IN EResponseCode code)
{
return (INT32) code >= 200 && (INT32) code < 300;
}
} // namespace IACore

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -83,7 +83,7 @@ namespace IACore
SocketOps::Close(m_socket); // SocketOps gracefully handles INVALID_SOCKET
}
Expected<VOID, String> IPC_Node::Connect(IN PCCHAR connectionString)
EXPECT(VOID) IPC_Node::Connect(IN PCCHAR connectionString)
{
auto desc = IPC_ConnectionDescriptor::Deserialize(connectionString);
m_shmName = desc.SharedMemPath;
@ -287,8 +287,7 @@ namespace IACore
}
}
Expected<NativeProcessID, String> IPC_Manager::SpawnNode(IN CONST FilePath &executablePath,
IN UINT32 sharedMemorySize)
EXPECT(NativeProcessID) IPC_Manager::SpawnNode(IN CONST FilePath &executablePath, IN UINT32 sharedMemorySize)
{
auto session = std::make_unique<NodeSession>();
@ -364,7 +363,7 @@ namespace IACore
puts(std::format(__CC_MAGENTA "[Node:{}:STDOUT|STDERR]: {}" __CC_DEFAULT, sid, line).c_str());
#endif
},
[sid](IN Expected<INT32, String> result) {
[sid](IN EXPECT(INT32) result) {
UNUSED(sid);
UNUSED(result);
#if __IA_DEBUG

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -17,7 +17,7 @@
namespace IACore
{
Expected<nlohmann::json, String> JSON::Parse(IN CONST String &json)
EXPECT(nlohmann::json) JSON::Parse(IN CONST String &json)
{
const auto parseResult = nlohmann::json::parse(json, nullptr, false, true);
if (parseResult.is_discarded())
@ -25,8 +25,7 @@ namespace IACore
return parseResult;
}
Expected<Pair<SharedPtr<simdjson::dom::parser>, simdjson::dom::object>, String> JSON::ParseReadOnly(
IN CONST String &json)
EXPECT(Pair<SharedPtr<simdjson::dom::parser>, simdjson::dom::object>) JSON::ParseReadOnly(IN CONST String &json)
{
auto parser = std::make_shared<simdjson::dom::parser>();

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -42,8 +42,10 @@ namespace IACore
#endif
}
Expected<INT32, String> ProcessOps::SpawnProcessSync(IN CONST String &command, IN CONST String &args,
IN Function<VOID(IN StringView line)> onOutputLineCallback)
EXPECT(INT32)
ProcessOps::SpawnProcessSync(IN CONST String &command, IN CONST String &args,
IN Function<VOID(IN StringView line)> onOutputLineCallback)
{
Atomic<NativeProcessID> id;
#if IA_PLATFORM_WINDOWS
@ -55,7 +57,7 @@ namespace IACore
SharedPtr<ProcessHandle> ProcessOps::SpawnProcessAsync(IN CONST String &command, IN CONST String &args,
IN Function<VOID(IN StringView line)> onOutputLineCallback,
IN Function<VOID(Expected<INT32, String>)> onFinishCallback)
IN Function<VOID(EXPECT(INT32))> onFinishCallback)
{
SharedPtr<ProcessHandle> handle = std::make_shared<ProcessHandle>();
handle->IsRunning = true;
@ -108,19 +110,20 @@ namespace IACore
namespace IACore
{
#if IA_PLATFORM_WINDOWS
Expected<INT32, String> ProcessOps::SpawnProcessWindows(IN CONST String &command, IN CONST String &args,
IN Function<VOID(StringView)> onOutputLineCallback,
OUT Atomic<NativeProcessID> &id)
EXPECT(INT32)
ProcessOps::SpawnProcessWindows(IN CONST String &command, IN CONST String &args,
IN Function<VOID(StringView)> onOutputLineCallback, OUT Atomic<NativeProcessID> &id)
{
SECURITY_ATTRIBUTES saAttr = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE}; // Allow inheritance
HANDLE hRead = NULL, hWrite = NULL;
if (!CreatePipe(&hRead, &hWrite, &saAttr, 0))
return tl::make_unexpected("Failed to create pipe");
return MakeUnexpected("Failed to create pipe");
// Ensure the read handle to the pipe for STDOUT is NOT inherited
if (!SetHandleInformation(hRead, HANDLE_FLAG_INHERIT, 0))
return tl::make_unexpected("Failed to secure pipe handles");
return MakeUnexpected("Failed to secure pipe handles");
STARTUPINFOA si = {sizeof(STARTUPINFOA)};
si.dwFlags |= STARTF_USESTDHANDLES;
@ -141,7 +144,7 @@ namespace IACore
if (!success)
{
CloseHandle(hRead);
return tl::make_unexpected(String("CreateProcess failed: ") + std::to_string(GetLastError()));
return MakeUnexpected(String("CreateProcess failed: ") + std::to_string(GetLastError()));
}
id.store(pi.dwProcessId);
@ -172,19 +175,20 @@ namespace IACore
#endif
#if IA_PLATFORM_UNIX
Expected<INT32, String> ProcessOps::SpawnProcessPosix(IN CONST String &command, IN CONST String &args,
IN Function<VOID(StringView)> onOutputLineCallback,
OUT Atomic<NativeProcessID> &id)
EXPECT(INT32)
ProcessOps::SpawnProcessPosix(IN CONST String &command, IN CONST String &args,
IN Function<VOID(StringView)> onOutputLineCallback, OUT Atomic<NativeProcessID> &id)
{
int pipefd[2];
if (pipe(pipefd) == -1)
return tl::make_unexpected("Failed to create pipe");
return MakeUnexpected("Failed to create pipe");
pid_t pid = fork();
if (pid == -1)
{
return tl::make_unexpected("Failed to fork process");
return MakeUnexpected("Failed to fork process");
}
else if (pid == 0)
{

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -17,7 +17,7 @@
namespace IACore
{
Expected<XML::Document, String> XML::ParseFromString(IN CONST String &data)
EXPECT(XML::Document) XML::ParseFromString(IN CONST String &data)
{
Document doc;
const auto parseResult = doc.load_string(data.data());
@ -26,7 +26,7 @@ namespace IACore
return IA_MOVE(doc);
}
Expected<XML::Document, String> XML::ParseFromFile(IN CONST FilePath &path)
EXPECT(XML::Document) XML::ParseFromFile(IN CONST FilePath &path)
{
Document doc;
const auto parseResult = doc.load_file(path.string().c_str());

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -40,13 +40,13 @@ namespace IACore
STATIC CompressionType DetectCompression(IN Span<CONST UINT8> data);
STATIC Expected<Vector<UINT8>, String> GZipInflate(IN Span<CONST UINT8> data);
STATIC Expected<Vector<UINT8>, String> GZipDeflate(IN Span<CONST UINT8> data);
STATIC EXPECT(Vector<UINT8>) GZipInflate(IN Span<CONST UINT8> data);
STATIC EXPECT(Vector<UINT8>) GZipDeflate(IN Span<CONST UINT8> data);
STATIC Expected<Vector<UINT8>, String> ZlibInflate(IN Span<CONST UINT8> data);
STATIC Expected<Vector<UINT8>, String> ZlibDeflate(IN Span<CONST UINT8> data);
STATIC EXPECT(Vector<UINT8>) ZlibInflate(IN Span<CONST UINT8> data);
STATIC EXPECT(Vector<UINT8>) ZlibDeflate(IN Span<CONST UINT8> data);
STATIC Expected<Vector<UINT8>, String> ZstdInflate(IN Span<CONST UINT8> data);
STATIC Expected<Vector<UINT8>, String> ZstdDeflate(IN Span<CONST UINT8> data);
STATIC EXPECT(Vector<UINT8>) ZstdInflate(IN Span<CONST UINT8> data);
STATIC EXPECT(Vector<UINT8>) ZstdDeflate(IN Span<CONST UINT8> data);
};
} // namespace IACore

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -61,7 +61,7 @@ namespace IACore
// Automatically detects extension (.dll/.so) if not provided
NO_DISCARD("Check for load errors")
STATIC tl::expected<DynamicLib, String> Load(CONST String &searchPath, CONST String &name)
STATIC tl::EXPECT(DynamicLib) Load(CONST String &searchPath, CONST String &name)
{
namespace fs = std::filesystem;
@ -84,7 +84,7 @@ namespace IACore
HMODULE h = LoadLibraryA(fullPath.string().c_str());
if (!h)
{
return tl::make_unexpected(GetWindowsError());
return MakeUnexpected(GetWindowsError());
}
lib.m_handle = CAST(h, PVOID);
#else
@ -94,7 +94,7 @@ namespace IACore
{
// dlerror returns a string describing the last error
const char *err = dlerror();
return tl::make_unexpected(String(err ? err : "Unknown dlopen error"));
return MakeUnexpected(String(err ? err : "Unknown dlopen error"));
}
lib.m_handle = h;
#endif
@ -104,35 +104,35 @@ namespace IACore
NO_DISCARD("Check if symbol exists")
tl::expected<PVOID, String> GetSymbol(CONST String &name) CONST
tl::EXPECT(PVOID) GetSymbol(CONST String &name) CONST
{
if (!m_handle)
return tl::make_unexpected(String("Library not loaded"));
return MakeUnexpected(String("Library not loaded"));
PVOID sym = nullptr;
#if IA_PLATFORM_WINDOWS
sym = CAST(GetProcAddress(CAST(m_handle, HMODULE), name.c_str()), PVOID);
if (!sym)
return tl::make_unexpected(GetWindowsError());
return MakeUnexpected(GetWindowsError());
#else
// Clear any previous error
dlerror();
sym = dlsym(m_handle, name.c_str());
const char *err = dlerror();
if (err)
return tl::make_unexpected(String(err));
return MakeUnexpected(String(err));
#endif
return sym;
}
// Template helper for casting
template<typename FuncT> tl::expected<FuncT, String> GetFunction(CONST String &name) CONST
template<typename FuncT> tl::EXPECT(FuncT) GetFunction(CONST String &name) CONST
{
auto res = GetSymbol(name);
if (!res)
return tl::make_unexpected(res.error());
return MakeUnexpected(res.error());
return REINTERPRET(*res, FuncT);
}

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -49,8 +49,8 @@ namespace IACore
TRUNCATE_EXISTING // Opens existing and clears it
};
STATIC Expected<NativeFileHandle, String> NativeOpenFile(IN CONST FilePath &path, IN EFileAccess access,
IN EFileMode mode, IN UINT32 permissions = 0644);
STATIC EXPECT(NativeFileHandle) NativeOpenFile(IN CONST FilePath &path, IN EFileAccess access,
IN EFileMode mode, IN UINT32 permissions = 0644);
STATIC VOID NativeCloseFile(IN NativeFileHandle handle);
public:
@ -58,21 +58,21 @@ namespace IACore
public:
STATIC VOID UnmapFile(IN PCUINT8 mappedPtr);
STATIC Expected<PCUINT8, String> MapFile(IN CONST FilePath &path, OUT SIZE_T &size);
STATIC EXPECT(PCUINT8) MapFile(IN CONST FilePath &path, OUT SIZE_T &size);
// @param `isOwner` TRUE to allocate/truncate. FALSE to just open.
STATIC Expected<PUINT8, String> MapSharedMemory(IN CONST String &name, IN SIZE_T size, IN BOOL isOwner);
STATIC EXPECT(PUINT8) MapSharedMemory(IN CONST String &name, IN SIZE_T size, IN BOOL isOwner);
STATIC VOID UnlinkSharedMemory(IN CONST String &name);
STATIC Expected<StreamReader, String> StreamFromFile(IN CONST FilePath &path);
STATIC Expected<StreamWriter, String> StreamToFile(IN CONST FilePath &path, IN BOOL overwrite = false);
STATIC EXPECT(StreamReader) StreamFromFile(IN CONST FilePath &path);
STATIC EXPECT(StreamWriter) StreamToFile(IN CONST FilePath &path, IN BOOL overwrite = false);
STATIC Expected<String, String> ReadTextFile(IN CONST FilePath &path);
STATIC Expected<Vector<UINT8>, String> ReadBinaryFile(IN CONST FilePath &path);
STATIC Expected<SIZE_T, String> WriteTextFile(IN CONST FilePath &path, IN CONST String &contents,
IN BOOL overwrite = false);
STATIC Expected<SIZE_T, String> WriteBinaryFile(IN CONST FilePath &path, IN Span<UINT8> contents,
IN BOOL overwrite = false);
STATIC EXPECT(String) ReadTextFile(IN CONST FilePath &path);
STATIC EXPECT(Vector<UINT8>) ReadBinaryFile(IN CONST FilePath &path);
STATIC EXPECT(SIZE_T)
WriteTextFile(IN CONST FilePath &path, IN CONST String &contents, IN BOOL overwrite = false);
STATIC EXPECT(SIZE_T)
WriteBinaryFile(IN CONST FilePath &path, IN Span<UINT8> contents, IN BOOL overwrite = false);
private:
STATIC UnorderedMap<PCUINT8, Tuple<PVOID, PVOID, PVOID>> s_mappedFiles;
@ -90,7 +90,7 @@ namespace IACore
MemoryMappedRegion(MemoryMappedRegion &&other) NOEXCEPT;
MemoryMappedRegion &operator=(MemoryMappedRegion &&other) NOEXCEPT;
Expected<VOID, String> Map(NativeFileHandle handle, UINT64 offset, SIZE_T size);
EXPECT(VOID) Map(NativeFileHandle handle, UINT64 offset, SIZE_T size);
VOID Unmap();
VOID Flush();

View File

@ -0,0 +1,90 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <IACore/Http/Common.hpp>
namespace IACore
{
class HttpClient : public HttpCommon
{
public:
STATIC EXPECT(UniquePtr<HttpClient>) Create(IN CONST String &host);
~HttpClient();
public:
EXPECT(String)
RawGet(IN CONST String &path, IN Span<CONST Header> headers,
IN PCCHAR defaultContentType = "application/x-www-form-urlencoded");
EXPECT(String)
RawPost(IN CONST String &path, IN Span<CONST Header> headers, IN CONST String &body,
IN PCCHAR defaultContentType = "application/x-www-form-urlencoded");
template<typename _response_type>
EXPECT(_response_type)
JsonGet(IN CONST String &path, IN Span<CONST Header> headers);
template<typename _payload_type, typename _response_type>
EXPECT(_response_type)
JsonPost(IN CONST String &path, IN Span<CONST Header> headers, IN CONST _payload_type &body);
// Certificate verfication is enabled by default
VOID EnableCertificateVerfication();
VOID DisableCertificateVerfication();
public:
EResponseCode LastResponseCode()
{
return m_lastResponseCode;
}
private:
httplib::Client m_client;
EResponseCode m_lastResponseCode;
private:
String PreprocessResponse(IN CONST String &response);
protected:
HttpClient(IN httplib::Client &&client);
};
template<typename _response_type>
EXPECT(_response_type)
HttpClient::JsonGet(IN CONST String &path, IN Span<CONST Header> headers)
{
const auto rawResponse = RawGet(path, headers, "application/json");
if (!rawResponse)
return MakeUnexpected(rawResponse.error());
if (LastResponseCode() != EResponseCode::OK)
return MakeUnexpected(std::format("Server responded with code {}", (INT32) LastResponseCode()));
return JSON::ParseToStruct<_response_type>(*rawResponse);
}
template<typename _payload_type, typename _response_type>
EXPECT(_response_type)
HttpClient::JsonPost(IN CONST String &path, IN Span<CONST Header> headers, IN CONST _payload_type &body)
{
const auto encodedBody = IA_TRY(JSON::EncodeStruct(body));
const auto rawResponse = RawPost(path, headers, encodedBody, "application/json");
if (!rawResponse)
return MakeUnexpected(rawResponse.error());
if (LastResponseCode() != EResponseCode::OK)
return MakeUnexpected(std::format("Server responded with code {}", (INT32) LastResponseCode()));
return JSON::ParseToStruct<_response_type>(*rawResponse);
}
} // namespace IACore

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -17,9 +17,11 @@
#include <IACore/JSON.hpp>
#include <httplib.h>
namespace IACore
{
class HttpClient
class HttpCommon
{
public:
enum class EHeaderType
@ -129,24 +131,6 @@ namespace IACore
using Header = KeyValuePair<String, String>;
public:
HttpClient(IN CONST String &host);
~HttpClient();
public:
Expected<String, String> RawGet(IN CONST String &path, IN Span<CONST Header> headers,
IN PCCHAR defaultContentType = "application/x-www-form-urlencoded");
Expected<String, String> RawPost(IN CONST String &path, IN Span<CONST Header> headers, IN CONST String &body,
IN PCCHAR defaultContentType = "application/x-www-form-urlencoded");
template<typename _response_type>
Expected<_response_type, String> JsonGet(IN CONST String &path, IN Span<CONST Header> headers);
template<typename _payload_type, typename _response_type>
Expected<_response_type, String> JsonPost(IN CONST String &path, IN Span<CONST Header> headers,
IN CONST _payload_type &body);
public:
STATIC String UrlEncode(IN CONST String &value);
STATIC String UrlDecode(IN CONST String &value);
@ -157,50 +141,16 @@ namespace IACore
STATIC BOOL IsSuccessResponseCode(IN EResponseCode code);
public:
EResponseCode LastResponseCode()
{
return m_lastResponseCode;
}
private:
PVOID m_client{};
EResponseCode m_lastResponseCode;
private:
String PreprocessResponse(IN CONST String &response);
protected:
HttpCommon() = default;
};
template<typename _response_type>
Expected<_response_type, String> HttpClient::JsonGet(IN CONST String &path, IN Span<CONST Header> headers)
{
const auto rawResponse = RawGet(path, headers, "application/json");
if (!rawResponse)
return MakeUnexpected(rawResponse.error());
if (LastResponseCode() != EResponseCode::OK)
return MakeUnexpected(std::format("Server responded with code {}", (INT32) LastResponseCode()));
return JSON::ParseToStruct<_response_type>(*rawResponse);
}
template<typename _payload_type, typename _response_type>
Expected<_response_type, String> HttpClient::JsonPost(IN CONST String &path, IN Span<CONST Header> headers,
IN CONST _payload_type &body)
{
const auto encodedBody = IA_TRY(JSON::EncodeStruct(body));
const auto rawResponse = RawPost(path, headers, encodedBody, "application/json");
if (!rawResponse)
return MakeUnexpected(rawResponse.error());
if (LastResponseCode() != EResponseCode::OK)
return MakeUnexpected(std::format("Server responded with code {}", (INT32) LastResponseCode()));
return JSON::ParseToStruct<_response_type>(*rawResponse);
}
HttpClient::Header HttpClient::CreateHeader(IN EHeaderType key, IN CONST String &value)
HttpCommon::Header HttpCommon::CreateHeader(IN EHeaderType key, IN CONST String &value)
{
return std::make_pair(HeaderTypeToString(key), value);
}
HttpClient::Header HttpClient::CreateHeader(IN CONST String &key, IN CONST String &value)
HttpCommon::Header HttpCommon::CreateHeader(IN CONST String &key, IN CONST String &value)
{
return std::make_pair(key, value);
}

View File

@ -0,0 +1,27 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <IACore/Http/Common.hpp>
namespace IACore
{
class HttpServer : public HttpCommon
{
public:
HttpServer(IN CONST String &host, IN UINT32 port);
};
} // namespace IACore

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -22,7 +22,7 @@
# include <IACore/Logger.hpp>
# define IACORE_MAIN() \
Expected<INT32, String> _app_entry(IN CONST Vector<String> &args); \
EXPECT(INT32) _app_entry(IN CONST Vector<String> &args); \
int main(int argc, char *argv[]) \
{ \
int exitCode = 0; \
@ -44,7 +44,7 @@
IACore::Terminate(); \
return exitCode; \
} \
Expected<INT32, String> _app_entry(IN CONST Vector<String> &args)
EXPECT(INT32) _app_entry(IN CONST Vector<String> &args)
namespace IACore
{

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -73,17 +73,11 @@ namespace ia::iatest
template<typename T> std::string ToString(CONST T &value)
{
if constexpr (std::is_arithmetic_v<T>)
{
return std::to_string(value);
}
else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, const char *>)
{
return std::string("\"") + value + "\"";
}
else
{
return "{Object}"; // Fallback for complex types
}
return "{Object}";
}
template<typename T> std::string ToString(T *value)
@ -311,10 +305,8 @@ namespace ia::iatest
printf(__CC_CYAN "[IATest] Discovered %zu Test Blocks\n\n" __CC_DEFAULT, entries.size());
for (auto &entry : entries)
{
entry(r);
}
// The destructor of 'r' will automatically print the summary
return 0;
}
};

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -75,7 +75,7 @@ namespace IACore
// When Manager spawns a node, `connectionString` is passed
// as the first command line argument
Expected<VOID, String> Connect(IN PCCHAR connectionString);
EXPECT(VOID) Connect(IN PCCHAR connectionString);
VOID Update();
@ -129,8 +129,8 @@ namespace IACore
VOID Update();
Expected<NativeProcessID, String> SpawnNode(IN CONST FilePath &executablePath,
IN UINT32 sharedMemorySize = DEFAULT_NODE_SHARED_MEMORY_SIZE);
EXPECT(NativeProcessID)
SpawnNode(IN CONST FilePath &executablePath, IN UINT32 sharedMemorySize = DEFAULT_NODE_SHARED_MEMORY_SIZE);
BOOL WaitTillNodeIsOnline(IN NativeProcessID node);
VOID ShutdownNode(IN NativeProcessID node);

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -29,16 +29,16 @@ namespace IACore
STATIC CONSTEXPR AUTO GLAZE_JSON_OPTS = glz::opts{.error_on_unknown_keys = false};
public:
STATIC Expected<nlohmann::json, String> Parse(IN CONST String &json);
STATIC Expected<Pair<SharedPtr<simdjson::dom::parser>, simdjson::dom::object>, String> ParseReadOnly(
IN CONST String &json);
template<typename _object_type> STATIC Expected<_object_type, String> ParseToStruct(IN CONST String &json);
STATIC EXPECT(nlohmann::json) Parse(IN CONST String &json);
STATIC EXPECT(Pair<SharedPtr<simdjson::dom::parser>, simdjson::dom::object>)
ParseReadOnly(IN CONST String &json);
STATIC String Encode(IN nlohmann::json data);
template<typename _object_type> STATIC Expected<String, String> EncodeStruct(IN CONST _object_type &data);
template<typename _object_type> STATIC EXPECT(_object_type) ParseToStruct(IN CONST String &json);
template<typename _object_type> STATIC EXPECT(String) EncodeStruct(IN CONST _object_type &data);
};
template<typename _object_type> Expected<_object_type, String> JSON::ParseToStruct(IN CONST String &json)
template<typename _object_type> EXPECT(_object_type) JSON::ParseToStruct(IN CONST String &json)
{
_object_type result{};
const auto parseError = glz::read_json<GLAZE_JSON_OPTS>(result, json);
@ -47,7 +47,7 @@ namespace IACore
return result;
}
template<typename _object_type> Expected<String, String> JSON::EncodeStruct(IN CONST _object_type &data)
template<typename _object_type> EXPECT(String) JSON::EncodeStruct(IN CONST _object_type &data)
{
String result;
const auto encodeError = glz::write_json(data, result);

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -339,7 +339,7 @@
auto _ia_res = (expr); \
if (!_ia_res) \
{ \
return tl::make_unexpected(std::move(_ia_res.error())); \
return MakeUnexpected(std::move(_ia_res.error())); \
} \
}
@ -348,7 +348,7 @@
auto _ia_res = (expr); \
if (!_ia_res) \
{ \
return tl::make_unexpected(std::move(_ia_res.error())); \
return MakeUnexpected(std::move(_ia_res.error())); \
} \
std::move(*_ia_res); \
})
@ -358,7 +358,7 @@
auto _ia_res = (expr); \
if (!_ia_res) \
{ \
return tl::make_unexpected(std::move(_ia_res.error())); \
return MakeUnexpected(std::move(_ia_res.error())); \
} \
UNUSED(*_ia_res); \
}
@ -595,7 +595,7 @@ template<typename T, typename... Args> inline SharedPtr<T> MakeSharedProtected(A
return MakeShared<make_shared_enabler>(std::forward<Args>(args)...);
}
template<typename T, typename... Args> inline SharedPtr<T> MakeUniqueProtected(Args &&...args)
template<typename T, typename... Args> inline UniquePtr<T> MakeUniqueProtected(Args &&...args)
{
struct make_unique_enabler : public T
{
@ -610,7 +610,9 @@ template<typename T, typename... Args> inline SharedPtr<T> MakeUniqueProtected(A
template<typename _expected_type, typename _unexpected_type>
using Expected = tl::expected<_expected_type, _unexpected_type>;
ALIAS_FUNCTION(MakeUnexpected, tl::make_unexpected);
# define EXPECT(type) Expected<type, String>
# define EXPECT(...) Expected<__VA_ARGS__, String>
# define UNEXPECTED(...) MakeUnexpected(std::format(__VA_ARGS__))
using String = std::string;
using StringView = std::string_view;

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -48,20 +48,20 @@ namespace IACore
public:
STATIC NativeProcessID GetCurrentProcessID();
STATIC Expected<INT32, String> SpawnProcessSync(IN CONST String &command, IN CONST String &args,
IN Function<VOID(IN StringView line)> onOutputLineCallback);
STATIC EXPECT(INT32) SpawnProcessSync(IN CONST String &command, IN CONST String &args,
IN Function<VOID(IN StringView line)> onOutputLineCallback);
STATIC SharedPtr<ProcessHandle> SpawnProcessAsync(IN CONST String &command, IN CONST String &args,
IN Function<VOID(IN StringView line)> onOutputLineCallback,
IN Function<VOID(Expected<INT32, String>)> onFinishCallback);
IN Function<VOID(EXPECT(INT32))> onFinishCallback);
STATIC VOID TerminateProcess(IN CONST SharedPtr<ProcessHandle> &handle);
private:
STATIC Expected<INT32, String> SpawnProcessWindows(IN CONST String &command, IN CONST String &args,
IN Function<VOID(StringView)> onOutputLineCallback,
OUT Atomic<NativeProcessID> &id);
STATIC Expected<INT32, String> SpawnProcessPosix(IN CONST String &command, IN CONST String &args,
IN Function<VOID(StringView)> onOutputLineCallback,
OUT Atomic<NativeProcessID> &id);
STATIC EXPECT(INT32)
SpawnProcessWindows(IN CONST String &command, IN CONST String &args,
IN Function<VOID(StringView)> onOutputLineCallback, OUT Atomic<NativeProcessID> &id);
STATIC EXPECT(INT32)
SpawnProcessPosix(IN CONST String &command, IN CONST String &args,
IN Function<VOID(StringView)> onOutputLineCallback, OUT Atomic<NativeProcessID> &id);
};
} // namespace IACore

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -29,8 +29,8 @@ namespace IACore
};
public:
INLINE Expected<VOID, String> Read(IN PVOID buffer, IN SIZE_T size);
template<typename T> NO_DISCARD("Check for EOF") Expected<T, String> Read();
INLINE EXPECT(VOID) Read(IN PVOID buffer, IN SIZE_T size);
template<typename T> NO_DISCARD("Check for EOF") EXPECT(T) Read();
VOID Skip(SIZE_T amount)
{
@ -76,7 +76,7 @@ namespace IACore
CONST EStorageType m_storageType;
};
Expected<VOID, String> StreamReader::Read(IN PVOID buffer, IN SIZE_T size)
EXPECT(VOID) StreamReader::Read(IN PVOID buffer, IN SIZE_T size)
{
if B_UNLIKELY ((m_cursor + size > m_dataSize))
return MakeUnexpected(String("Unexpected EOF while reading"));
@ -87,7 +87,7 @@ namespace IACore
return {};
}
template<typename T> NO_DISCARD("Check for EOF") Expected<T, String> StreamReader::Read()
template<typename T> NO_DISCARD("Check for EOF") EXPECT(T) StreamReader::Read()
{
constexpr SIZE_T size = sizeof(T);

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -39,11 +39,11 @@ namespace IACore
return res;
}
INLINE STATIC tl::expected<Vector<UINT8>, String> HexStringToBinary(CONST StringView &hex)
INLINE STATIC EXPECT(Vector<UINT8>) HexStringToBinary(CONST StringView &hex)
{
if (hex.size() % 2 != 0)
{
return tl::make_unexpected(String("Hex string must have even length"));
return MakeUnexpected(String("Hex string must have even length"));
}
Vector<UINT8> out;
@ -69,7 +69,7 @@ namespace IACore
if (h == -1 || l == -1)
{
return tl::make_unexpected(String("Invalid hex character found"));
return MakeUnexpected(String("Invalid hex character found"));
}
out.push_back(CAST((h << 4) | l, UINT8));

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -28,8 +28,8 @@ namespace IACore
using Document = pugi::xml_document;
public:
STATIC Expected<Document, String> ParseFromString(IN CONST String &data);
STATIC Expected<Document, String> ParseFromFile(IN CONST FilePath &path);
STATIC EXPECT(Document) ParseFromString(IN CONST String &data);
STATIC EXPECT(Document) ParseFromFile(IN CONST FilePath &path);
STATIC String SerializeToString(IN CONST Node &node, IN BOOL escape = false);
STATIC String SerializeToString(IN CONST Document &doc, IN BOOL escape = false);

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@ -24,7 +24,8 @@
#error "TRUE macro is broken in C mode"
#endif
int main(void) {
int main(void)
{
IA_VERSION_TYPE version = IA_MAKE_VERSION(1, 0, 0);
IA_ASSERT(version > 0);

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -14,7 +14,7 @@
// limitations under the License.
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
#include <IACore/SIMD.hpp>
#include <IACore/IATest.hpp>

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.