Skip to content

Commit b3ae931

Browse files
authored
Merge pull request #5 from Siderust/handle-errors
Add error handling classes and enhance CMake for Rust integration
2 parents d6b83de + ef1a9f6 commit b3ae931

11 files changed

Lines changed: 379 additions & 398 deletions

File tree

.github/workflows/ci.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ jobs:
1919
runs-on: ubuntu-22.04
2020
env:
2121
CARGO_TERM_COLOR: always
22+
CLANG_FORMAT_BIN: clang-format-18
2223
steps:
2324
- name: Checkout (with submodules)
2425
uses: actions/checkout@v4
@@ -31,10 +32,14 @@ jobs:
3132
run: |
3233
set -euo pipefail
3334
sudo apt-get update
35+
sudo apt-get install -y --no-install-recommends ca-certificates wget
36+
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc >/dev/null
37+
echo "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-18 main" | sudo tee /etc/apt/sources.list.d/llvm-18.list >/dev/null
38+
sudo apt-get update
3439
sudo apt-get install -y --no-install-recommends \
3540
cmake \
3641
ninja-build \
37-
clang-format \
42+
clang-format-18 \
3843
clang-tidy
3944
4045
- name: Set up Rust (stable)
@@ -52,12 +57,7 @@ jobs:
5257
shell: bash
5358
run: |
5459
set -euo pipefail
55-
mapfile -t files < <(git ls-files '*.hpp' '*.cpp')
56-
if [ ${#files[@]} -eq 0 ]; then
57-
echo "No C++ files found."
58-
exit 0
59-
fi
60-
clang-format --dry-run --Werror "${files[@]}"
60+
./clang_format.sh --check --no-diff
6161
6262
- name: clang-tidy check
6363
shell: bash

CMakeLists.txt

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,28 @@ set(CMAKE_CXX_STANDARD 17)
55
set(CMAKE_CXX_STANDARD_REQUIRED ON)
66
set(CMAKE_CXX_EXTENSIONS OFF)
77
option(TEMPOCH_BUILD_DOCS "Enable Doxygen documentation target." ON)
8+
option(TEMPOCH_USE_CANONICAL_RUST
9+
"Build/link against ../../../rust/tempoch instead of the vendored snapshot."
10+
OFF)
811

912
# Find Cargo for building Rust library
1013
find_program(CARGO_BIN cargo REQUIRED)
1114

1215
# Paths to tempoch-ffi
13-
set(TEMPOCH_SUBMODULE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tempoch)
14-
set(TEMPOCH_FFI_DIR ${TEMPOCH_SUBMODULE_DIR}/tempoch-ffi)
16+
if(TEMPOCH_USE_CANONICAL_RUST)
17+
set(TEMPOCH_CANONICAL_RUST_DIR
18+
${CMAKE_CURRENT_SOURCE_DIR}/../../../rust/tempoch
19+
CACHE PATH "Path to the canonical rust/tempoch workspace")
20+
set(TEMPOCH_SUBMODULE_DIR ${TEMPOCH_CANONICAL_RUST_DIR})
21+
set(TEMPOCH_ARTIFACT_DIR ${TEMPOCH_CANONICAL_RUST_DIR}/target/release)
22+
set(TEMPOCH_TARGET_DIR ${TEMPOCH_CANONICAL_RUST_DIR}/target)
23+
else()
24+
set(TEMPOCH_SUBMODULE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tempoch)
25+
set(TEMPOCH_ARTIFACT_DIR ${TEMPOCH_SUBMODULE_DIR}/tempoch-ffi/target/release)
26+
set(TEMPOCH_TARGET_DIR ${TEMPOCH_SUBMODULE_DIR}/tempoch-ffi/target)
27+
endif()
28+
set(TEMPOCH_FFI_DIR ${TEMPOCH_SUBMODULE_DIR}/tempoch-ffi)
1529
set(TEMPOCH_FFI_INCLUDE_DIR ${TEMPOCH_FFI_DIR}/include)
16-
set(TEMPOCH_ARTIFACT_DIR ${TEMPOCH_FFI_DIR}/target/release)
1730

1831
# Allow enabling Cargo features for tempoch-ffi (e.g., serde)
1932
set(TEMPOCH_FFI_FEATURES "" CACHE STRING "Cargo features for tempoch-ffi (e.g., 'serde' or empty)")
@@ -43,7 +56,7 @@ endif()
4356
add_custom_target(
4457
build_tempoch_ffi
4558
COMMAND ${CMAKE_COMMAND} -E env
46-
CARGO_TARGET_DIR=${TEMPOCH_FFI_DIR}/target
59+
CARGO_TARGET_DIR=${TEMPOCH_TARGET_DIR}
4760
${CARGO_BIN} build --release ${_TEMPOCH_FEATURES_ARGS}
4861
WORKING_DIRECTORY ${TEMPOCH_FFI_DIR}
4962
BYPRODUCTS ${TEMPOCH_LIBRARY_PATH}
@@ -100,9 +113,17 @@ endif()
100113

101114
# Set RPATH for runtime library location
102115
if(APPLE)
103-
set(_tempoch_rpath "@loader_path/../tempoch/tempoch-ffi/target/release")
116+
if(TEMPOCH_USE_CANONICAL_RUST)
117+
set(_tempoch_rpath "${TEMPOCH_ARTIFACT_DIR}")
118+
else()
119+
set(_tempoch_rpath "@loader_path/../tempoch/tempoch-ffi/target/release")
120+
endif()
104121
elseif(UNIX)
105-
set(_tempoch_rpath "$ORIGIN/../tempoch/tempoch-ffi/target/release")
122+
if(TEMPOCH_USE_CANONICAL_RUST)
123+
set(_tempoch_rpath "${TEMPOCH_ARTIFACT_DIR}")
124+
else()
125+
set(_tempoch_rpath "$ORIGIN/../tempoch/tempoch-ffi/target/release")
126+
endif()
106127
endif()
107128

108129
# Only build tests, examples, and Google Test when standalone (not as subdirectory)

clang_format.sh

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
#! /usr/bin/env bash
2+
3+
set -euo pipefail
4+
5+
readonly ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6+
MODE=""
7+
SHOW_DIFF=1
8+
CLANG_FORMAT_BIN="${CLANG_FORMAT_BIN:-}"
9+
10+
usage() {
11+
cat <<'EOF'
12+
Usage: ./clang_format.sh [--check | --fix] [--no-diff] [--help]
13+
14+
Options:
15+
--check Check formatting and fail if files need changes.
16+
--fix Apply formatting changes in place.
17+
--no-diff In check mode, do not print unified diffs.
18+
--help Show this help message.
19+
20+
Environment:
21+
CLANG_FORMAT_BIN Path or command name to clang-format binary.
22+
EOF
23+
}
24+
25+
parse_args() {
26+
if [[ $# -eq 0 ]]; then
27+
MODE="check"
28+
return
29+
fi
30+
31+
while [[ $# -gt 0 ]]; do
32+
case "$1" in
33+
--check)
34+
MODE="check"
35+
;;
36+
--fix)
37+
MODE="fix"
38+
;;
39+
--no-diff)
40+
SHOW_DIFF=0
41+
;;
42+
--help|-h)
43+
usage
44+
exit 0
45+
;;
46+
*)
47+
echo "Unknown argument: $1" >&2
48+
usage >&2
49+
exit 2
50+
;;
51+
esac
52+
shift
53+
done
54+
55+
if [[ -z "$MODE" ]]; then
56+
echo "Select one mode: --check or --fix" >&2
57+
usage >&2
58+
exit 2
59+
fi
60+
}
61+
62+
resolve_clang_format() {
63+
if [[ -n "$CLANG_FORMAT_BIN" ]] && command -v "$CLANG_FORMAT_BIN" >/dev/null 2>&1; then
64+
return
65+
fi
66+
67+
for candidate in clang-format-18 clang-format clang-format-17 clang-format-16 clang-format-15 clang-format-14; do
68+
if command -v "$candidate" >/dev/null 2>&1; then
69+
CLANG_FORMAT_BIN="$candidate"
70+
return
71+
fi
72+
done
73+
74+
echo "clang-format binary not found. Install clang-format or set CLANG_FORMAT_BIN." >&2
75+
exit 1
76+
}
77+
78+
collect_files() {
79+
local file
80+
local -a collected=()
81+
82+
mapfile -t collected < <(git -C "$ROOT_DIR" ls-files '*.hpp' '*.cpp' | sort)
83+
84+
FILES=()
85+
for file in "${collected[@]}"; do
86+
FILES+=("$ROOT_DIR/$file")
87+
done
88+
}
89+
90+
check_files() {
91+
echo "Checking formatting with $CLANG_FORMAT_BIN"
92+
"$CLANG_FORMAT_BIN" --dry-run --Werror "${FILES[@]}"
93+
echo "clang-format check passed."
94+
}
95+
96+
fix_files() {
97+
local file
98+
99+
echo "Applying formatting with $CLANG_FORMAT_BIN"
100+
101+
for file in "${FILES[@]}"; do
102+
"$CLANG_FORMAT_BIN" -i "$file"
103+
done
104+
105+
echo "Formatting applied to ${#FILES[@]} files."
106+
}
107+
108+
main() {
109+
parse_args "$@"
110+
resolve_clang_format
111+
112+
cd "$ROOT_DIR"
113+
collect_files
114+
115+
if [[ ${#FILES[@]} -eq 0 ]]; then
116+
echo "No tracked .hpp or .cpp files found."
117+
exit 0
118+
fi
119+
120+
case "$MODE" in
121+
check) check_files ;;
122+
fix) fix_files ;;
123+
esac
124+
}
125+
126+
main "$@"

include/tempoch/civil_time.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ struct CivilTime {
3030
uint8_t day; ///< Day of month [1, 31].
3131
uint8_t hour; ///< Hour [0, 23].
3232
uint8_t minute; ///< Minute [0, 59].
33-
uint8_t second; ///< Second [0, 60] (leap-second aware).
33+
uint8_t second; ///< Second [0, 59].
3434
uint32_t nanosecond; ///< Nanosecond [0, 999 999 999].
3535

3636
/// Default constructor: J2000 epoch noon-like civil representation.

include/tempoch/ffi_core.hpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,32 @@ class NoIntersectionError : public TempochException {
6262
: TempochException(msg) {}
6363
};
6464

65+
/**
66+
* @brief The supplied raw scale identifier is invalid.
67+
*/
68+
class InvalidScaleIdError : public TempochException {
69+
public:
70+
explicit InvalidScaleIdError(const std::string &msg)
71+
: TempochException(msg) {}
72+
};
73+
74+
/**
75+
* @brief The supplied quantity does not represent a time duration.
76+
*/
77+
class InvalidDurationUnitError : public TempochException {
78+
public:
79+
explicit InvalidDurationUnitError(const std::string &msg)
80+
: TempochException(msg) {}
81+
};
82+
83+
/**
84+
* @brief Rust caught a panic before unwinding across the FFI boundary.
85+
*/
86+
class InternalPanicError : public TempochException {
87+
public:
88+
explicit InternalPanicError(const std::string &msg) : TempochException(msg) {}
89+
};
90+
6591
// ============================================================================
6692
// Error Translation
6793
// ============================================================================
@@ -83,6 +109,12 @@ inline void check_status(tempoch_status_t status, const char *operation) {
83109
throw InvalidPeriodError(msg + "invalid period (start > end)");
84110
case TEMPOCH_STATUS_T_NO_INTERSECTION:
85111
throw NoIntersectionError(msg + "periods do not intersect");
112+
case TEMPOCH_STATUS_T_INVALID_SCALE_ID:
113+
throw InvalidScaleIdError(msg + "invalid scale id");
114+
case TEMPOCH_STATUS_T_INVALID_DURATION_UNIT:
115+
throw InvalidDurationUnitError(msg + "invalid duration unit");
116+
case TEMPOCH_STATUS_T_INTERNAL_PANIC:
117+
throw InternalPanicError(msg + "internal panic");
86118
default:
87119
throw TempochException(msg + "unknown error (" + std::to_string(status) +
88120
")");

0 commit comments

Comments
 (0)