Skip to content

Commit f4bf0a6

Browse files
committed
feat(rix-io): initial IO module with File abstraction, readers/writers, utils and tests
- Introduce rix::io module with File RAII abstraction (text & binary). - Add FileMode / FileType API with std::ios openmode translation. - Implement reader & writer helpers for text and binary data. - Provide buffer utilities and IO helpers. - Add examples (read/write, temp files). - Add unit tests covering read/write paths. - Add CMake + Makefile build support. - Initial CHANGELOG for rix-io.
1 parent d1968b8 commit f4bf0a6

14 files changed

Lines changed: 950 additions & 0 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,4 @@
3939

4040
# debug information files
4141
*.dwo
42+
build/

CHANGELOG.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [Unreleased]
9+
## [0.1.0] - 2025-12-05
10+
11+
### Added
12+
-
13+
14+
### Changed
15+
-
16+
17+
### Removed
18+
-
19+
20+
21+
## [v0.1.0] - 2025-12-05
22+
23+
### Added
24+
25+
- Initial project scaffolding for the `vixcpp/websocket` module.
26+
- CMake build system:
27+
- STATIC vs header-only build depending on `src/` contents.
28+
- Integration with `vix::core` and optional JSON backend.
29+
- Support for sanitizers via `VIX_ENABLE_SANITIZERS`.
30+
- Basic repository structure:
31+
- `include/vix/websocket/` for public headers.
32+
- `src/` for implementation files.
33+
- Release workflow:
34+
- `Makefile` with `release`, `commit`, `push`, `merge`, and `tag` targets.
35+
- `changelog` target wired to `scripts/update_changelog.sh`.

CMakeLists.txt

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
# ====================================================================
2+
# Rix — IO Module
3+
# ====================================================================
4+
# Purpose:
5+
# Build configuration for the rix-io module.
6+
#
7+
# This module provides basic I/O utilities for Rix:
8+
# - simple file abstraction
9+
# - text/binary read & write helpers
10+
# - stream helpers
11+
#
12+
# Design:
13+
# - Header-only by default (INTERFACE library)
14+
# - If any .cpp files exist under src/, we switch to a STATIC lib
15+
#
16+
# Targets:
17+
# - rix_io : The actual library target (STATIC or INTERFACE)
18+
# - rix::io : Namespaced alias for consumers
19+
#
20+
# Installation:
21+
# - Installs headers under <prefix>/include/rix/...
22+
# - Contributes to the umbrella export-set `RixTargets`
23+
# ====================================================================
24+
25+
cmake_minimum_required(VERSION 3.20)
26+
project(rix_io VERSION 0.1.0 LANGUAGES CXX)
27+
28+
include(GNUInstallDirs)
29+
30+
# ------------------------ Global settings ----------------------------
31+
set(CMAKE_CXX_STANDARD 20)
32+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
33+
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
34+
35+
# Friendly warnings (can be tuned later if needed)
36+
set(RIX_IO_GLOBAL_CXX_FLAGS "-Wall -Wextra -Wshadow")
37+
set(CMAKE_CXX_FLAGS_RELEASE "${RIX_IO_GLOBAL_CXX_FLAGS} -O2 -DNDEBUG")
38+
set(CMAKE_CXX_FLAGS_DEBUG "${RIX_IO_GLOBAL_CXX_FLAGS} -g")
39+
40+
# ------------------------ Sources discovery --------------------------
41+
# If any .cpp exists under src/, we switch to STATIC build mode.
42+
file(GLOB_RECURSE RIX_IO_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
43+
44+
# ------------------------ Helper: Sanitizers (optional) --------------
45+
# This is opt-in and controlled by a top-level option if needed.
46+
option(RIX_IO_ENABLE_SANITIZERS "Enable address/UB sanitizers for rix-io" OFF)
47+
48+
function(rix_io_apply_sanitizers tgt scope)
49+
if (RIX_IO_ENABLE_SANITIZERS AND TARGET ${tgt})
50+
message(STATUS "[rix-io] enabling sanitizers on ${tgt} (${scope})")
51+
if (${scope} STREQUAL "PRIVATE")
52+
target_compile_options(${tgt} PRIVATE
53+
-O1 -g -fno-omit-frame-pointer -fsanitize=address,undefined)
54+
target_link_options(${tgt} PRIVATE
55+
-fsanitize=address,undefined)
56+
else()
57+
target_compile_options(${tgt} INTERFACE
58+
-O1 -g -fno-omit-frame-pointer -fsanitize=address,undefined)
59+
target_link_options(${tgt} INTERFACE
60+
-fsanitize=address,undefined)
61+
endif()
62+
endif()
63+
endfunction()
64+
65+
# ============================== STATIC ===============================
66+
if (RIX_IO_SOURCES)
67+
message(STATUS "[rix-io] Building STATIC library with detected sources.")
68+
69+
add_library(rix_io STATIC ${RIX_IO_SOURCES})
70+
add_library(rix::io ALIAS rix_io)
71+
target_compile_features(rix_io PUBLIC cxx_std_20)
72+
73+
target_include_directories(rix_io
74+
PUBLIC
75+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
76+
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
77+
)
78+
79+
# Sanitizers (opt-in)
80+
rix_io_apply_sanitizers(rix_io PRIVATE)
81+
82+
set_target_properties(rix_io PROPERTIES
83+
OUTPUT_NAME rix_io
84+
VERSION ${PROJECT_VERSION}
85+
SOVERSION 0
86+
EXPORT_NAME io
87+
)
88+
89+
install(TARGETS rix_io
90+
EXPORT RixTargets
91+
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
92+
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
93+
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
94+
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
95+
)
96+
97+
# ============================ HEADER-ONLY ============================
98+
else()
99+
message(STATUS "[rix-io] Building HEADER-ONLY library (no sources).")
100+
101+
add_library(rix_io INTERFACE)
102+
add_library(rix::io ALIAS rix_io)
103+
target_compile_features(rix_io INTERFACE cxx_std_20)
104+
105+
target_include_directories(rix_io INTERFACE
106+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
107+
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
108+
)
109+
110+
# Propagate sanitizers to dependents if requested
111+
rix_io_apply_sanitizers(rix_io INTERFACE)
112+
113+
install(TARGETS rix_io
114+
EXPORT RixTargets
115+
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
116+
)
117+
endif()
118+
119+
# ------------------------ Options local build ------------------------
120+
option(RIX_IO_BUILD_TESTS "Build rix-io tests" ON)
121+
option(RIX_IO_BUILD_EXAMPLES "Build rix-io examples" ON)
122+
123+
# ----------------------------- Tests --------------------------------
124+
if (RIX_IO_BUILD_TESTS)
125+
enable_testing()
126+
127+
add_executable(rix_io_tests
128+
${CMAKE_CURRENT_SOURCE_DIR}/tests/file_test.cpp
129+
)
130+
131+
target_link_libraries(rix_io_tests PRIVATE rix_io)
132+
133+
# Include dirs arrivent via rix_io (PUBLIC / INTERFACE), donc pas besoin
134+
# d'en rajouter ici.
135+
136+
# Optionnel : activer les sanitizers aussi pour les tests
137+
rix_io_apply_sanitizers(rix_io_tests PRIVATE)
138+
139+
add_test(NAME rix_io_file_test COMMAND rix_io_tests)
140+
endif()
141+
142+
# ---------------------------- Examples -------------------------------
143+
if (RIX_IO_BUILD_EXAMPLES)
144+
add_executable(rix_io_read_write
145+
${CMAKE_CURRENT_SOURCE_DIR}/examples/read_write.cpp
146+
)
147+
148+
target_link_libraries(rix_io_read_write PRIVATE rix_io)
149+
150+
# Optionnel : sanitizers sur l'exemple aussi
151+
rix_io_apply_sanitizers(rix_io_read_write PRIVATE)
152+
endif()
153+
154+
155+
# ------------------------ Headers install ----------------------------
156+
install(DIRECTORY include/
157+
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
158+
FILES_MATCHING PATTERN "*.hpp" PATTERN "*.h")
159+
160+
# ----------------------------- Summary -------------------------------
161+
message(STATUS "------------------------------------------------------")
162+
message(STATUS "rix::io configured (${PROJECT_VERSION})")
163+
if (RIX_IO_SOURCES)
164+
message(STATUS "Mode: STATIC / sources found")
165+
else()
166+
message(STATUS "Mode: HEADER-ONLY / no sources")
167+
endif()
168+
message(STATUS "Include dir: ${CMAKE_CURRENT_SOURCE_DIR}/include (for <rix/...>)")
169+
message(STATUS "Sanitizers enabled: ${RIX_IO_ENABLE_SANITIZERS}")
170+
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
171+
message(STATUS "------------------------------------------------------")

Makefile

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
VERSION ?= v0.1.0
2+
BRANCH_DEV = dev
3+
BRANCH_MAIN = main
4+
RETRIES ?= 3
5+
SLEEP ?= 2
6+
7+
.PHONY: help release commit push push_main merge tag test changelog return_dev
8+
9+
help:
10+
@echo "Available commands:"
11+
@echo " make commit - Add and commit all files (on $(BRANCH_DEV) branch)"
12+
@echo " make push - Push the $(BRANCH_DEV) branch (with retry)"
13+
@echo " make push_main - Push the $(BRANCH_MAIN) branch (with retry)"
14+
@echo " make merge - Merge $(BRANCH_DEV) into $(BRANCH_MAIN) and push"
15+
@echo " make tag VERSION=vX.Y.Z - Create and push a Git tag (default: $(VERSION), with retry)"
16+
@echo " make release VERSION=vX.Y.Z - Full release workflow"
17+
@echo " make test - Run tests"
18+
@echo " make changelog - Update CHANGELOG.md"
19+
20+
return_dev:
21+
@current=$$(git rev-parse --abbrev-ref HEAD); \
22+
if [ "$$current" != "$(BRANCH_DEV)" ]; then \
23+
echo "↩️ Returning to $(BRANCH_DEV)..."; \
24+
git checkout $(BRANCH_DEV); \
25+
fi
26+
27+
commit:
28+
@git checkout $(BRANCH_DEV)
29+
@if [ -n "$$(git status --porcelain)" ]; then \
30+
echo "📝 Committing changes on $(BRANCH_DEV)..."; \
31+
git add .; \
32+
git commit -m "chore(release): prepare $(VERSION)"; \
33+
else \
34+
echo "✅ Nothing to commit on $(BRANCH_DEV)."; \
35+
fi
36+
@$(MAKE) return_dev
37+
38+
push:
39+
@echo "⬆️ Pushing $(BRANCH_DEV) to origin (with retry, $(RETRIES)x max)..."
40+
@git checkout $(BRANCH_DEV)
41+
@n=0; \
42+
until [ $$n -ge $(RETRIES) ]; do \
43+
if git push origin $(BRANCH_DEV); then \
44+
echo "✅ Push of $(BRANCH_DEV) succeeded."; \
45+
break; \
46+
fi; \
47+
n=$$((n+1)); \
48+
echo "⚠️ Push failed. Retry $$n/$(RETRIES) in $(SLEEP)s..."; \
49+
sleep $(SLEEP); \
50+
done; \
51+
if [ $$n -ge $(RETRIES) ]; then \
52+
echo "❌ Push of $(BRANCH_DEV) failed after $(RETRIES) attempts."; \
53+
exit 1; \
54+
fi
55+
@$(MAKE) return_dev
56+
57+
push_main:
58+
@echo "⬆️ Pushing $(BRANCH_MAIN) to origin (with retry, $(RETRIES)x max)..."
59+
@git checkout $(BRANCH_MAIN)
60+
@n=0; \
61+
until [ $$n -ge $(RETRIES) ]; do \
62+
if git push origin $(BRANCH_MAIN); then \
63+
echo "✅ Push of $(BRANCH_MAIN) succeeded."; \
64+
break; \
65+
fi; \
66+
n=$$((n+1)); \
67+
echo "⚠️ Push failed. Retry $$n/$(RETRIES) in $(SLEEP)s..."; \
68+
sleep $(SLEEP); \
69+
done; \
70+
if [ $$n -ge $(RETRIES) ]; then \
71+
echo "❌ Push of $(BRANCH_MAIN) failed after $(RETRIES) attempts."; \
72+
exit 1; \
73+
fi
74+
@$(MAKE) return_dev
75+
76+
merge:
77+
@echo "🔀 Merging $(BRANCH_DEV) into $(BRANCH_MAIN)..."
78+
@git checkout $(BRANCH_MAIN)
79+
@git merge --no-ff --no-edit $(BRANCH_DEV)
80+
@$(MAKE) push_main
81+
@$(MAKE) return_dev
82+
83+
tag:
84+
@if git rev-parse $(VERSION) >/dev/null 2>&1; then \
85+
echo "❌ Tag $(VERSION) already exists."; \
86+
exit 1; \
87+
else \
88+
echo "🏷️ Creating annotated tag $(VERSION)..."; \
89+
git tag -a $(VERSION) -m "Release version $(VERSION)"; \
90+
echo "⬆️ Pushing tag $(VERSION) (with retry)..."; \
91+
n=0; \
92+
until [ $$n -ge $(RETRIES) ]; do \
93+
if git push origin $(VERSION); then \
94+
echo "✅ Tag $(VERSION) pushed successfully."; \
95+
break; \
96+
fi; \
97+
n=$$((n+1)); \
98+
echo "⚠️ Push tag failed. Retry $$n/$(RETRIES) in $(SLEEP)s..."; \
99+
sleep $(SLEEP); \
100+
done; \
101+
if [ $$n -ge $(RETRIES) ]; then \
102+
echo "❌ Pushing tag $(VERSION) failed after $(RETRIES) attempts."; \
103+
exit 1; \
104+
fi; \
105+
fi
106+
@$(MAKE) return_dev
107+
108+
release:
109+
@$(MAKE) changelog
110+
@$(MAKE) commit
111+
@$(MAKE) push
112+
@$(MAKE) merge
113+
@$(MAKE) tag VERSION=$(VERSION)
114+
@$(MAKE) return_dev
115+
116+
test:
117+
cd build && ctest --output-on-failure
118+
119+
changelog:
120+
bash scripts/update_changelog.sh
121+
@$(MAKE) return_dev

examples/read_write.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#include <iostream>
2+
#include <string>
3+
4+
#include "rix/io/util.hpp"
5+
#include "rix/io/writer.hpp"
6+
#include "rix/io/reader.hpp"
7+
8+
using namespace rix::io;
9+
10+
static int run_example()
11+
{
12+
auto path = temp_file_path("rix_io_example");
13+
14+
std::cout << "[rix-io] Example file: " << path << "\n";
15+
16+
std::string content =
17+
"Rix IO example\n"
18+
"--------------\n"
19+
"This file was created by rix::io.\n";
20+
21+
write_text(path, content);
22+
23+
auto loaded = read_text(path);
24+
25+
std::cout << "[rix-io] Loaded content:\n";
26+
std::cout << "------------------------\n";
27+
std::cout << loaded << "\n";
28+
29+
// cleanup best-effort
30+
std::error_code ec;
31+
std::filesystem::remove(path, ec);
32+
33+
return 0;
34+
}
35+
36+
int main()
37+
{
38+
try
39+
{
40+
return run_example();
41+
}
42+
catch (const std::exception &ex)
43+
{
44+
std::cerr << "[rix-io] Example failed: " << ex.what() << "\n";
45+
return 1;
46+
}
47+
}

0 commit comments

Comments
 (0)