# **IACore - C++ Style Guide** This document defines the coding standards for IACore and all IA Projects. Philosophy: Enforce Rust-like memory safety and discipline within modern C++20. --- ### **1. Oxide Usage** Usage of [`Oxide`](https://github.com/I-A-S/Oxide) library and its philosophy is mandatory. `Oxide` is a single header library and a truncated version of it is listed below. ```cpp #define OX_UNUSED(v) (void)(v) namespace Oxide { // ============================================================================= // Primitive Types // ============================================================================= using u8 = std::uint8_t; using u16 = std::uint16_t; using u32 = std::uint32_t; using u64 = std::uint64_t; using i8 = std::int8_t; using i16 = std::int16_t; using i32 = std::int32_t; using i64 = std::int64_t; using f32 = float; using f64 = double; using usize = std::size_t; using isize = std::ptrdiff_t; // ============================================================================= // Template Types // ============================================================================= template using Const = const T; template using Mut = T; template using Ref = const T &; template using MutRef = T &; template using ForwardRef = T &&; // ============================================================================= // Memory & Ownership // ============================================================================= template using Box = std::unique_ptr; template using Arc = std::shared_ptr; template using Weak = std::weak_ptr; template [[nodiscard]] inline auto make_box(ForwardRef... args) -> Box { return std::make_unique(std::forward(args)...); } template [[nodiscard]] inline auto make_arc(ForwardRef... args) -> Arc { return std::make_shared(std::forward(args)...); } // ============================================================================= // Error Handling // ============================================================================= template using Result = Oxide::Internal::Expected; template [[nodiscard]] inline auto fail(ForwardRef error) { return Oxide::Internal::make_unexpected(std::forward(error)); } template [[nodiscard]] inline auto fail(Ref> fmt, ForwardRef... args) { return Oxide::Internal::make_unexpected( std::format(fmt, std::forward(args)...)); } // ============================================================================= // Utilities // ============================================================================= namespace Env { #if defined(NDEBUG) constexpr Const IS_DEBUG = false; constexpr Const IS_RELEASE = true; #else constexpr Const IS_DEBUG = true; constexpr Const IS_RELEASE = false; #endif } // namespace Env [[noreturn]] inline void panic(Ref msg, Ref loc = std::source_location::current()) { std::cerr << "\n[panic] " << msg << "\n At: " << loc.file_name() << ":" << loc.line() << "\n"; std::abort(); } inline void ensure(Const condition, Ref msg, Ref loc = std::source_location::current()) { if (Env::IS_DEBUG && !condition) { std::cerr << "\n[assert] " << msg << "\n At: " << loc.file_name() << ":" << loc.line() << "\n"; std::abort(); } } using String = std::string; using StringView = std::string_view; template using Option = std::optional; template using Vec = std::vector; template using Span = std::span; template using Pair = std::pair; template using Array = std::array; } // namespace Oxide #define OX_TRY_PURE(expr) \ { \ auto _ox_res = (expr); \ if (!_ox_res) { \ return Oxide::Internal::make_unexpected(std::move(_ox_res.error())); \ } \ } #define OX_TRY(expr) \ __extension__({ \ auto _ox_res = (expr); \ if (!_ox_res) { \ return Oxide::Internal::make_unexpected(std::move(_ox_res.error())); \ } \ std::move(*_ox_res); \ }) #define OX_TRY_DISCARD(expr) \ { \ auto _ox_res = (expr); \ if (!_ox_res) { \ return Oxide::Internal::make_unexpected(std::move(_ox_res.error())); \ } \ OX_UNUSED(*_ox_res); \ } ``` Note: no need to explicity use `Oxide::` prefix as Oxide namespace is almost always globally used in IA projects. All variables (local, member and parameter/argument) MUST always be wrapped in one of `Const, Mut, Ref, MutRef` or `ForwardRef`. > For outer most template of parameters/arguments, use the following Rule to decide between `Ref` or `Const`: > 1) Is the parameter size <= 64, then use `Const` > 2) Otherwise use `Ref` | Use This | Instead of This | | :---- | :---- | | ```Box``` | ```std::unique_ptr``` | | ```Arc``` | ```std::shared_ptr``` | | ```Weak``` | ```std::weak_ptr``` | | ```make_box``` | ```std::make_unique``` | | ```make_arc``` | ```std::make_shared``` | --- ### **2. Naming Conventions** We use **Rust Naming Conventions** to strictly distinguish Types from Values. | Element | Style | Example | | :---- | :---- | :---- | | **Types / Classes** | PascalCase | ```StreamReader, TcpSocket``` | | **Functions** | snake_case | ```read_bytes(), create_instance()``` | | **Variables** | snake_case | ```buffer_size, socket_id``` | | **Private Members** | m_snake_case | ```m_parser, m_data_size``` | | **Constants** | SCREAMING_SNAKE | ```MAX_PATH_LENGTH``` | | **Namespaces** | PascalCase | ```IACore, Oxide, IACore::Env``` | | **Files** | PascalCase | ```StreamReader.hpp``` | **Rule:** Never use Hungarian notation (e.g., iCount, strName) except for the m_ prefix on private members. --- ### **3. Primitives Types** Do not use standard C++ primitives (int, long, unsigned int, double, char). Use the IACore Rust Aliases defined in IACore.hpp. | Use This | Instead of This | | :---- | :---- | | ```i8, i16, i32, i64``` | ```int8_t, short, int, long long``` | | ```u8, u16, u32, u64``` | ```uint8_t, unsigned short, unsigned int``` | | ```f32, f64``` | ```float, double``` | | ```usize``` | ```size_t, std::size_t``` | | ```isize``` | ```std::ptrdiff_t``` | **Exception:** Use char only for C-string literals or std::format compatibility. --- ### **4. Ownership & Pointers** Adhere to strict ownership semantics. **Raw pointers (T\*) are non-owning.** * **Box (ia::Box):** Exclusive ownership. Use ia::make_box(). * **Arc (ia::Arc):** Shared ownership (atomic ref-counting). Use sparingly. * **Raw Pointers (T\*):** Borrowed, non-owning, mutable view. **Must not be deleted.** * **Const Pointers (const T\*):** Borrowed, non-owning, read-only view. **Forbidden:** * new / delete / malloc / free. * Passing std::shared_ptr by value (unless sharing ownership is the intent). --- ### **5. Error Handling** Exceptions are BANNED. All fallible functions must return ia::Result. **Correct:** ```cpp // Returns value OR error string auto read_file(const Path& path) -> ia::Result; ``` Checking Errors (The IA_TRY Macro): Use IA_TRY to propagate errors (equivalent to Rust's ? operator). ```cpp auto process_data() -> Result { IA_TRY(auto data, read_file("test.txt")); // Returns error if read_file fails return process(data); } ``` --- ### **6. Function Signatures** Use **Trailing Return Syntax** for all functions (even void returns). This aligns with Rust (fn name() -> type) and handles complex template returns better. **Correct:** ```cpp auto calculate_sum(u32 a, u32 b) -> u32; auto do_something() -> void; ``` **Incorrect:** ```cpp u32 calculate_sum(u32 a, u32 b); void do_something(); ``` --- ### **7. Const Correctness and Auto Usage** Immutable by Default. `auto` keyword is BANNED. Variables should be const unless mutation is explicitly required. **Correct:** ```cpp Const path = "data.bin"; Const result = process(path); ``` **Incorrect:** ```cpp String path = "data.bin"; const auto result = process(path); ``` --- ### **8. Macros** Avoid Macros. Use constexpr for constants and inline templates for logic. * **Allowed:** IA_TRY, IA_NODISCARD, Platform detection (internal). * **Banned:** TRUE, FALSE, CONST, IN, OUT. ### **9. Class Design (The "Safe Wrapper" Pattern)** If a class wraps a C-library or raw resource (like simdjson), it must: 1. Be **Move-Only** (Delete Copy Constructor). 2. Use a **Factory Method** (create()) that returns Result> or Result. 3. Never expose raw handles that outlive the wrapper. ```cpp class SafeWrapper { public: static auto create() -> Result; SafeWrapper(SafeWrapper&&) = default; SafeWrapper(const SafeWrapper&) = delete; }; ``` ---